Оскільки тестована частина Yii побудована на PHPUnit, рекомендується спочатку вивчити документацію PHPUnit, щоб отримати загальне уявлення про те, як писати модульні тести. Далі ми наведемо основні принципи написання модульних тестів в Yii:
Модульний тест — це клас XyzTest
, що успадковує клас CTestCase або CDbTestCase, де Xyz
— назва тестованого класу. Наприклад, для тестування класу Post
за угодою ми називаємо відповідний клас модульного тесту PostTest
. Базовий клас CTestCase призначений для загального модульного тестування, а клас CDbTestCase — для тестування класів моделей Active Record. Ми можемо використовувати всі методи цих класів, успадкованих від класу PHPUnit_Framework_TestCase
, оскільки він — предок обох класів (CTestCase і CDbTestCase).
Клас модульного тесту зберігається в PHP-файлі з імʼям XyzTest.php
. За угодою файл модульного тесту може бути збережено в директорії protected/tests/unit
.
Основний зміст тестового класу — набір тестових методів з іменами виду testAbc
, де Abc
— часто імʼя тестованого методу класу.
Зазвичай тестовий метод містить послідовність виразів тверджень (наприклад, assertTrue
, assertEquals
), які служать контрольними точками при перевірці поведінки цільового класу.
Далі ми опишемо, як писати модульні тести для класів моделей 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);
}