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

Поскольку тестировочная часть 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);
}
~~~