2017 © Pedro Peláez
 

library db-fixture-manager

DbFixture manager for functional tests

image

uglide/db-fixture-manager

DbFixture manager for functional tests

  • Wednesday, April 10, 2013
  • by uglide
  • Repository
  • 1 Watchers
  • 0 Stars
  • 828 Installations
  • PHP
  • 0 Dependents
  • 0 Suggesters
  • 0 Forks
  • 0 Open issues
  • 2 Versions
  • 0 % Grown

The README.md

DbFixtureManager

DbFixtureManager- создан с целью упростить управление фикстурами БД и подготовку тестового окружения для выполнения тестов., (*1)

Проблематика

Для лучшего понимания происходящего, рассмотрим следующий тривиальный пример:, (*2)

Предположим, что в нашей системе разработан некий модуль shops, функционал которого покрыт различными тестами (модульными и функциональными): , (*3)

Допустим, что наша текущая задача - добавить тест для этого модуля, который нуждается в фикстуре магазина добавленной в БД. Смотря на файловую структуру тестов для shops модуля, мы можем сделать предположение, что фикстура магазина и код, который добавляет ее в БД уже есть в каком-то из тестов., (*4)

Проблема № 1 - Необходимо просмотреть все тесты данного модуля, для того, чтобы определить есть ли необходимый код для подготовки тестового окружения или нет.

Проблема № 2 - Проблема №1 влечет за собой дублирование кода в тестах, что существенно увеличивает их хрупкость и делает более сложным добавление новых тестов.

После титанических усилий мы все таки находим некий код, который добавляет фикстуру магазина, например:, (*5)

public static function setUpShop() { $shop = $shops->createRow(self::$fixtures['shop']); $shop->save(); return $shop; }, (*6)

Мы добавляем его вызов в тест, и должны не забыть удалить фикстуру из БД после окончания теста, (*7)

Проблема № 3 - Необходимость "ручного" контроля очистки фикстур

Но в ходе написания тестов очень часто возникает необходимость подготовить несколько связанных сущностей в БД и тут возникает следующая проблема:, (*8)

Проблема № 4 - Неявные зависимости между тест кейсами за счет перекрестного использования методов для подготовки БД

Решение

Использование DbFixtureManager :), (*9)

Для начала необходимо создать класс - контейнер для фикстур:, (*10)

, (*11)

Класс наследуется от uglide\DbFixtureManager\ContainerAbstract:, (*12)

use uglide\DbFixtureManager\ContainerAbstract;
class Shops_Fixtures_Container extends ContainerAbstract
{
    ...
}

В данном классе необходимо определить методы для подготовки окружения, в данном случае это будет setUpShop(), (*13)

  use uglide\DbFixtureManager\ContainerAbstract;
  class Shops_Fixtures_Container extends ContainerAbstract
    {

     public static $fixtures = array(
            'shop' =array(
                'id' =1,
                'alias' ='testshop',
                'name' ='Test Shop',
                'country_id'    = 1,
                'state_id'  = 25,
                'city_id'   = 28
            )
        );

        /**
         * @param array $config
         *
         * @return array
         */

        public function setUpShop($config = array('resetTable' =true))
        {

            $shops = new Shops_Model_Shop_Table();
            $shops->getDefaultAdapter()->query('SET FOREIGN_KEY_CHECKS=0;');
            if (isset($config['resetTable']) && $config['resetTable']) {
                $shops->delete(' true = true ');
            }

            $shop = $shops->createRow(self::$fixtures['shop']);
            $shop->save();

            /**
             * Register cleaner
             */
            $this->_registerCleaner('_tearDownShop');
            return $fixture;
        }

        protected function _tearDownShop()
        {
            $shops = new Shops_Model_Shop_Table();
            $shops->getDefaultAdapter()->query('SET FOREIGN_KEY_CHECKS=0;');
            $shops->delete(' true = true ');
        }
}

! Метод, который поднимает фикстуру обязательно должен регистрировать сборщик мусора (cleaner). Cleaner - это метод, который будет вызван автоматически для удаления поднятой фикстуры., (*14)

Также необходимо определить загрузчик контейнеров фикстур, например его можно определить в bootstrap.php:, (*15)

/**
 * Init Fixtures loader
 */
spl_autoload_register(function($className) {
        $matches = array();

        if (preg_match('/([a-z]+)_Fixtures_Container/i', $className, $matches)) {
            $path = __DIR__ . '/fixtures/' . $matches[1] . '.php';

            if (file_exists($path)) {
                require_once $path;
            }
        }
    });

Далее необходимо унаследовать абстрактный класс тест кейса, и реализовать метод получения объекта для работы с Бд, (*16)

use uglide\DbFixtureManager\TestCase;

class BaseTestCase extends TestCase
{

    protected function getDb()
    {
        return Database::instance();
    }

}

Все тест-кейсы с фикстурами будут наследоваться от этого класса, (*17)

Как использовать в тестах:, (*18)


// Example 1 /** * Самый простой случай - нам необходимо добавить в БД фикстуру, * которая не используется после этого в тесте * @fixture Shops::setUpShop */ public function testIndexAction() { // код теста } // Example 2 /** * Добавляем в БД фикстуру, * и результат выполнения метода setUpShop будем использовать в тесте * @fixture $shop Shops::setUpShop */ public function testIndexAction() { // .... $this->_fixture['shop']; // фикстура доступна по указанному имени в массиве $this->_fixtures // .... } // Example 3 /** * Добавляем в БД фикстуру, с помощью метода setUpShop, * которому нужно передать определенные параметры * знак "+" после названия метода обозначает, * что в данный метод будет передана фикстура * из дата-провайдера в качестве аргумента * @fixture $shop Shops::setUpShop+ * @dataProvider shopDataProvider */ public function testIndexAction($fixtureSettings) // фикстура передаваемая дата-провайдером доступна как аргумент теста { // .... $this->_fixture['shop']; // фикстура доступна по указанному имени в массиве $this->_fixtures // .... } /** * Стандартный дата-провайдер PHPUnit */ public function shopDataProvider() { return array('validTest' => array('resetTable' => false)); } // Example 4 /** * Добавляем в БД несколько фикстур, * @fixture $shop Shops::setUpShop * @fixture $user Users::setUpUser */ public function testIndexAction() { // .... $this->_fixture['shop']; $this->_fixture['user']; // .... } //Example 5 /** * Добавляем в БД несколько фикстур, * с помощью нескольких методов. * Обратите внимание на то, что методы * получают различные данные из дата провайдера * @fixture $shop Shops::setUpShop * @fixture $user Users::setUpUser * @dataProvider shopDataProvider */ public function testIndexAction() { // .... $this->_fixture['shop']; $this->_fixture['user']; // .... } /** * Стандартный дата-провайдер PHPUnit */ public function shopDataProvider() { return array( 'validTest' => array( 'setUpShop' => array('resetTable' => false), //эти данные будут переданы в Shops::setUpShop 'setUpUser' => array('id' => 100), // а эти в Users::setUpUser ) ); }

Использование фикстур из контейнера, (*19)

Как вы уже догадываетесь из заголовка, в данном менеджере фикстур есть возможность использовать фикстуры непосредственно из контейнера., (*20)

Предположим, у нас есть следующий контейнер с фикстурами:, (*21)

        use uglide\DbFixtureManager\ContainerAbstract;
        class Shops_Fixtures_Container extends ContainerAbstract
    {

        /**
         * Фикстуры должны быть добавлены в статическую
         * переменную класса $fixtures
         */

         public static $fixtures = array(
            'shop' => array(
                'id' => 1,
                'alias' => 'testshop',
                'name' => 'Test Shop',
                'country_id'    =>  1,
                'state_id'  =>  25,
                'city_id'   =>  28
            )
        );
     }

Данную фикстуру мы можем использовать в тестах следующим образом:, (*22)


// Example 1 /** * Указываем имя переменной, * в которую будет записана фикстура * и имя фикстуры со знаком $ * @fixture $superShop Shops::$shop */ public function testIndexAction() { // .... // теперь мы можем использовать в тесте // фикстуру $this->_fixture['superShop']; // .... } // Example 2 /** * Если имя целевой переменной не указано явно, * то фикстура будет доступна в массиве * $this->_fixture по своему индексу * из контейнера * @fixture Shops::$shop */ public function testIndexAction() { // .... // теперь мы можем использовать в тесте // фикстуру $this->_fixture['shop']; // .... }

Но зачем это, если можно просто вызвать в тесте статическую переменную контейнера?!, (*23)

Работая с фикстурами через менеджер у вас есть возможность получать динамически созданные фикстуры:, (*24)

        use uglide\DbFixtureManager\ContainerAbstract;
        class Shops_Fixtures_Container extends ContainerAbstract
    {
        /**
         * Статическая фикстура
         */
         public static $fixtures = array(
            'shop' => array(
                'id' => 1,
                'alias' => 'testshop',
                'name' => 'Test Shop',
                'country_id'    =>  1,
                'state_id'  =>  25,
                'city_id'   =>  28
            )
        );

        public function __construct(Zend_Db_Adapter_Abstract $dbAdapter)
        {
            parent::__construct($dbAdapter);

            // генерируем фикстуру 
            self::$fixtures['someGeneratedFixture'] = $this->someShopFixtureGenerator();
        }

        // .......
     }

    /**
         * Мы можем получить динамически созданную
         * фикстуру в тесте
         * @fixture $someGeneratedFixture Shops::$someGeneratedFixture
         */
        public function testIndexAction()
        {
            // ....
            $this->_fixture['someGeneratedFixture'];
            // ....
        }

Преимущества

  • автоматическое удаление фикстур, об организации которого нужно побеспокоиться только 1 раз на этапе создания метода, для подъема фикстуры
  • тесты не захламляются большим количеством кода для поднятия фикстур и за счет этого мы получаем более чистые и понятные тесты
  • фикстуры для БД каждого модуля собраны в одном месте и ими проще управлять
  • получение динамически созданных фикстур

The Versions

10/04 2013

dev-master

9999999-dev https://github.com/uglide/db-fixture-manager

DbFixture manager for functional tests

  Sources   Download

MIT

The Requires

 

by Igor Malinovskiy

tests db fixture

10/04 2013

0.1

0.1.0.0 https://github.com/uglide/db-fixture-manager

DbFixture manager for functional tests

  Sources   Download

MIT

The Requires

 

by Igor Malinovskiy

tests db fixture