Тестирование моделей в CakePHP
Мне понравилось тестировать как можно больше всего в CakePHP. О том как тестировать компоненты, я уже писал, теперь пришло время моделей.
В поисках подходящего the fucking manual я набрёл на Testing Models with CakePHP 1.2 test suite на bakery.cakephp.org.
И всё очень хорошо расписано, но, блин, не работает и всё. Поэтому не читайте то, что там написано. Я тщательно изучив исходники методом научного тыка сделал так, чтобы всё работало.
Идеология тестирования моделей в CakePHP
Модели работают с базой данных и соответственно надо проверить насколько хорошо это получается. Я сторонник fat Models, thin Controllers и стараюсь переносить всю логику работы с данными в модели. Поэтому проверять надо много.
Можно указать отдельное подключение для тестовой базы данных в app/config/database.php в переменной $test. Обычно подходят те же значения, что и в $default. Если вы уберёте $test, то CakePHP сам установит её такой же как и $default. В любом случае, не волнуйтесь, потому что для тестовых таблиц будет добавлен префикс test_suite.
Для создания тестовых таблиц используются fixtures. Они создают тестовые таблицы до проведения теста, перед каждым тестом загружают туда тестовые данные, после каждого теста очищают тестовые таблицы и после последнего теста удаляют их.
Создание Fixtures
Как говорится "сначала было слово", вот мы и создадим fixture для модели Word.
app/test/fixtures/word_test_fixture.php
Эта fixture создаст таблицу test_suite_words ($useTable), и возьмёт поля с таблицы, которую использует модель Word ($import). После этого она заполнит их записями из $records.
Обычно лучше вносить свои тестовые данные, но если надо брать данные из существующей таблицы то надо $import определить так
Тогда $records указвать не нужно. Вместо model можно указать table. Также можно указать connection.
При желании можно было бы не брать поля из существующей таблицы, а вручную указать их. Это может быть удобно, если таблица ещё не создана. Вот этот же пример с указаниеми полей.
-
<?
-
-
class WordTestFixture extends CakeTestFixture {
-
var $name = 'WordTest';
-
var $useTable = 'words';
-
'created' => 'datetime',
-
);
-
-
);
-
}
-
-
?>
Опции для $fields:
- type: VARCHAR - string, TEXT - text, INT - integer, FLOAT - float, DATETIME - datetime, TIMESTAMP - timestamp, TIME - time, DATE - date, BLOB - binary
- key: primary, если поле AUTO_INCREMENT и PRIMARY KEY
- length: если надо указать длину
- null: если true, то разрешить NULL, если false, то запретить NULL
- default: значение по умолчанию
Если не надо задавать дополнительных опций, то можно писать одной строкой, не создавая массив. Так например сделано в предыдущем примере для created.
Созание теста
Загружаем тестируемую модель
-
loadModel('Word');
Для того, чтобы использовать fixtures, надо создать потомка тестируемой модели и уже его тестировать.
-
class WordTest extends Word {
-
var $name = 'WordTest';
-
var $useTable = 'words';
-
var $useDbConfig = 'test_suite';
-
}
Дописываем тест и получаем
app/tests/cases/models/word.test.php
-
<?php
-
-
loadModel('Word');
-
-
class WordTest extends Word {
-
var $name = 'WordTest';
-
var $useTable = 'words';
-
var $useDbConfig = 'test_suite';
-
}
-
-
-
class WordTestCase extends CakeTestCase {
-
var $model = null;
-
-
function setUp() {
-
}
-
-
function testCreate() {
-
$this->model =& new WordTest();
-
}
-
-
function testListFlipLow() {
-
$result = $this->model->generateListFlipLow();
-
'table' => 1,
-
'boy' => 2,
-
'girl' => 3,
-
);
-
$this->assertEqual($result, $expected);
-
}
-
-
function testAdd() {
-
$result = $this->model->add('Test');
-
$this->assertEqual($result, 4);
-
-
$result = $this->model->generateListFlipLow();
-
'table' => 1,
-
'boy' => 2,
-
'girl' => 3,
-
'test' => 4,
-
);
-
$this->assertEqual($result, $expected);
-
}
-
-
function tearDown() {
-
}
-
}
-
?>
Обратите внимание, что setUp и tearDown запускаются до и после каждого теста.
А теперь сама модель из
app/models/word.php
-
<?php
-
class Word extends AppModel {
-
-
var $name = 'Word';
-
'id' => VALID_NUMBER,
-
'name' => VALID_NOT_EMPTY,
-
);
-
-
/**
-
* Adds a word and returns id
-
*
-
* @param string $name
-
* @return integer If failed to save returns false
-
*/
-
function add($name) {
-
'name' => $name,
-
);
-
$this->create();
-
if ($this->save($item)) {
-
return $this->getInsertId();
-
} else {
-
return false;
-
}
-
}
-
-
/**
-
* Generates list of lowercase names and its ids
-
*
-
* @return array (a(name=>id), ...)
-
*/
-
function generateListFlipLow(&$model) {
-
$items = $this->generateList();
-
foreach ($items as $id=>$name) {
-
$items[$id] = low($name);
-
}
-
-
}
-
}
-
?>
Запускаем server.com/test.php и радуемся тому, что тесты работают
[...] , . [...]
, )
. - .
[...] я уже писал, я люблю выносить обработку данных в модели. При этом у [...]
Привет, а есть что нибудь по тестированию контроллеров? У них (разработчиков) там что-то непонятно, сделали они что нибудь для этого в 1.2 или нет. Нашел решение от 2006 года, но оно для 1.1, да и хочется что нибудь совсем родного, а не костыли прикручивать..
http://www.thinkingphp.org/2006/08/24/controller-testing-in-cakephp/ - это решение.