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