Модульне тестування

Оскільки тестована частина Yii побудована на PHPUnit, рекомендується спочатку вивчити документацію PHPUnit, щоб отримати загальне уявлення про те, як писати модульні тести. Далі ми наведемо основні принципи написання модульних тестів в Yii:

Далі ми опишемо, як писати модульні тести для класів моделей Active Record. Ми розширюємо наші тестові класи, наслідуючи їх від класу CDbTestCase, оскільки він забезпечує підтримку фікстур бази даних, які ми представили у попередньому розділі.

Припустимо, що ми хочемо перевірити клас моделі Comment у демо-блозі. Почнемо зі створення класу CommentTest і збережемо його у файлі protected/tests/unit/CommentTest.php:

class CommentTest extends CDbTestCase
{
    public $fixtures=array(
        'posts'=>'Post',
        'comments'=>'Comment',
    );
 
    …
}

У цьому класі ми визначаємо змінну-член класу fixtures масивом, що містить перелік фікстур, що використовуються в даному тесті. Масив являє собою відображення імен фікстур на імена класів моделей або імена таблиць фікстур (наприклад, фікстура з імʼям posts на клас моделі Post). Зауважимо, що при відображенні на імʼя таблиці фікстури ми повинні використовувати імʼя таблиці з префіксом : (наприклад, :Post), щоб відрізняти його від імені класу моделі. А при використанні імен класів моделей, відповідні таблиці будуть розглядатися у якості таблиць фікстур. Як описано вище, таблиці фікстур будуть скинуті в деякий відомий стан щоразу при виконанні тестового методу.

Імʼя фікстури дозволяє нам отримати зручний доступ до даних фікстури у тестових методах. Наступний код показує типове використання:

// повертає всі рядки таблиці фікстур `Comment`
$comments = $this->comments;
// повертає рядок з псевдонімом 'sample1' у таблиці фікстур `Post`
$post = $this->posts['sample1'];
// повертає екземпляр класу AR, що представляє рядок даних фікстури 'sample1'
$post = $this->posts('sample1');

Примітка: Якщо фікстура оголошена з використанням імені її таблиці (наприклад, 'posts'=>':Post'), то третій приклад в коді вище не є допустимим, оскільки ми не маємо інформації про те, який клас моделі асоційований з таблицею.

Далі ми пишемо метод testApprove для тестування методу approve в класі моделі Comment. Код дуже прямолінійний: спочатку ми вставляємо коментар зі статусом очікування, потім перевіряємо, коментар має статус очікування або інший, витягуючи його з бази даних, і, нарешті, ми викликаємо метод approve і перевіряємо, чи змінився статус, як очікувалося.

public function testApprove()
{
    // вставити коментар до листа очікування
    $comment=new Comment;
    $comment->setAttributes(array(
        'content'=>'comment 1',
        'status'=>Comment::STATUS_PENDING,
        'createTime'=>time(),
        'author'=>'me',
        'email'=>'me@example.com',
        'postId'=>$this->posts['sample1']['id'],
    ),false);
    $this->assertTrue($comment->save(false));
 
    // перевірити наявність коментаря в листі очікування
    $comment=Comment::model()->findByPk($comment->id);
    $this->assertTrue($comment instanceof Comment);
    $this->assertEquals(Comment::STATUS_PENDING,$comment->status);
 
    // викликати метод approve() і перевірити, що коментар затверджено
    $comment->approve();
    $this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
    $comment=Comment::model()->findByPk($comment->id);
    $this->assertEquals(Comment::STATUS_APPROVED,$comment->status);
}