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

Оскільки тестована частина Yii побудована на [PHPUnit](http://www.phpunit.de/), рекомендується спочатку вивчити [документацію PHPUnit](http://www.phpunit.de/manual/current/en/index.html), щоб отримати загальне уявлення про те, як писати модульні тести. Далі ми наведемо основні принципи написання модульних тестів в Yii:

 * Модульний тест — це клас `XyzTest`, що успадковує клас [CTestCase] або [CDbTestCase], де `Xyz` — назва тестованого класу. Наприклад, для тестування класу `Post` за угодою ми називаємо відповідний клас модульного тесту `PostTest`. Базовий клас [CTestCase] призначений для загального модульного тестування, а клас [CDbTestCase] — для тестування класів моделей [Active Record](/doc/guide/database.ar). Ми можемо використовувати всі методи цих класів, успадкованих від класу `PHPUnit_Framework_TestCase`, оскільки він — предок обох класів ([CTestCase] і [CDbTestCase]).

 * Клас модульного тесту зберігається в PHP-файлі з імʼям `XyzTest.php`. За угодою файл модульного тесту може бути збережено в директорії `protected/tests/unit`.

 * Основний зміст тестового класу — набір тестових методів з іменами виду `testAbc`, де `Abc`— часто імʼя тестованого методу класу.

 * Зазвичай тестовий метод містить послідовність виразів тверджень (наприклад, `assertTrue`, `assertEquals`), які служать контрольними точками при перевірці поведінки цільового класу.

Далі ми опишемо, як писати модульні тести для класів моделей [Active Record](/doc/guide/database.ar). Ми розширюємо наші тестові класи, наслідуючи їх від класу [CDbTestCase], оскільки він забезпечує підтримку фікстур бази даних, які ми представили у попередньому розділі.

Припустимо, що ми хочемо перевірити клас моделі `Comment` у [демо-блозі](http://www.yiiframework.com/demos/blog/). Почнемо зі створення класу `CommentTest` і збережемо його у файлі `protected/tests/unit/CommentTest.php`:

~~~
[php]
class CommentTest extends CDbTestCase
{
	public $fixtures=array(
		'posts'=>'Post',
		'comments'=>'Comment',
	);

	…
}
~~~

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

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

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

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

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

~~~
[php]
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);
}
~~~