Home PageКаталог Изменения НовыеКомментарии Пользователи Регистрация
CakePHP: Articles/Tutorials/TestingModels ...

Тестирование моделей в CakePHP

Автор Владимир Лучанинов


Мне понравилось тестировать как можно больше всего в CakePHP. О том как тестировать компоненты, я уже писал, теперь пришло время моделей.


В поисках подходящего the fucking manual я набрёл на Testing Models with CakePHP 1.2 test suite на bakery.cakephp.org.
И всё очень хорошо расписано, но, блин, не работает и всё. Поэтому не читайте то, что там написано. Я тщательно изучив исходники методом научного тыка сделал так, чтобы всё работало.

Идеология тестирования моделей в Cake PHP?

Модели работают с базой данных и соответственно надо проверить насколько хорошо это получается. Я сторонник fat Models, thin Controllers и стараюсь переносить всю логику работы с данными в модели. Поэтому проверять надо много.


Можно указать отдельное подключение для тестовой базы данных в app/config/database.php в переменной $test. Обычно подходят те же значения, что и в $default. Если вы уберёте $test, то Cake PHP? сам установит её такой же как и $default. В любом случае, не волнуйтесь, потому что для тестовых таблиц будет добавлен префикс test_suite.


Для создания тестовых таблиц используются fixtures. Они создают тестовые таблицы до проведения теста, перед каждым тестом загружают туда тестовые данные, после каждого теста очищают тестовые таблицы и после последнего теста удаляют их.

Создание Fixtures

Как говорится «сначала было слово», вот мы и создадим fixture для модели Word.


app/test/fixtures/word_test_fixture.php

<?
    
class WordTestFixture extends CakeTestFixture {
        var 
$name 'WordTest';
        var 
$useTable 'words';
        var 
$import 'Word';

        var 
$records = array(
            array(
'id'=>1'name'=>'Table'),
            array(
'id'=>2'name'=>'boy'),
            array(
'id'=>3'name'=>'girl'),
        );
    }
?>


Эта fixture создаст таблицу test_suite_words ($useTable), и возьмёт поля с таблицы, которую использует модель Word ($import). После этого она заполнит их записями из $records.


Обычно лучше вносить свои тестовые данные, но если надо брать данные из существующей таблицы то надо $import определить так

var $import = array('model' => 'Word', 'records' => true);


Тогда $records указвать не нужно. Вместо model можно указать table. Также можно указать connection.


При желании можно было бы не брать поля из существующей таблицы, а вручную указать их. Это может быть удобно, если таблица ещё не создана. Вот этот же пример с указаниеми полей.


<?
    
class WordTestFixture extends CakeTestFixture {
        var 
$name 'WordTest';
        var 
$useTable 'words';
        var 
$fields = array(
            
'id' => array('type'=>'integer''key'=>'primary'),
            
'name' => array('type'=>'string''length'=>255'null'=>false),
            
'created' => 'datetime',
        );

        var 
$records = array(
            array(
'id'=>1'name'=>'Table'),
            array(
'id'=>2'name'=>'boy'),
            array(
'id'=>3'name'=>'girl'),
        );
    }
?>


Опции для $fields:


Если не надо задавать дополнительных опций, то можно писать одной строкой, не создавая массив. Так например сделано в предыдущем примере для 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 
$fixtures = array('word_test');
        var 
$model null;

        function 
setUp() { }

        function 
testCreate() {
            
$this->model =& new WordTest();
        }

        function 
testListFlipLow() {
            
$result $this->model->generateListFlipLow();
            
$expected = array(
                
'table' => 1,
                
'boy'   => 2,
                
'girl'  => 3,
            );
            
$this->assertEqual($result$expected);
        }

        function 
testAdd() {
            
$result $this->model->add('Test');
            
$this->assertEqual($result4);

            
$result $this->model->generateListFlipLow();
            
$expected = array(
                
'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';
        var 
$validate = array(
            
'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) {
            
$item = array(
                
'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);
            }

            return 
array_flip($items);
        }
    }
?>


Запускаем http://server.com/test.php и радуемся тому, что тесты работают.


 
Комментарии
Добавить комментарий:

Файлов нет. [Показать файлы/форму]