PHPackages                             uglide/db-fixture-manager - PHPackages - PHPackages  [Skip to content](#main-content)[PHPackages](/)[Directory](/)[Categories](/categories)[Trending](/trending)[Leaderboard](/leaderboard)[Changelog](/changelog)[Analyze](/analyze)[Collections](/collections)[Log in](/login)[Sign up](/register)

1. [Directory](/)
2. /
3. [Testing &amp; Quality](/categories/testing)
4. /
5. uglide/db-fixture-manager

ActiveLibrary[Testing &amp; Quality](/categories/testing)

uglide/db-fixture-manager
=========================

DbFixture manager for functional tests

0.1(13y ago)0837MITPHPPHP &gt;=5.3.0

Since Apr 10Pushed 12y ago1 watchersCompare

[ Source](https://github.com/uglide/db-fixture-manager)[ Packagist](https://packagist.org/packages/uglide/db-fixture-manager)[ Docs](https://github.com/uglide/db-fixture-manager)[ RSS](/packages/uglide-db-fixture-manager/feed)WikiDiscussions master Synced 1mo ago

READMEChangelog (1)Dependencies (1)Versions (2)Used By (0)

DbFixtureManager
================

[](#dbfixturemanager)

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

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

[](#проблематика)

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

Предположим, что в нашей системе разработан некий модуль shops, функционал которого покрыт различными тестами (модульными и функциональными): [![](https://camo.githubusercontent.com/28d4af06c43652886d4de4bddbfe39528f510bdc6015832187beac7b926df6cb/687474703a2f2f676c6964652e6e616d652f646f63732f7a66632d7472616e736974696f6e2f6d666d2f312e504e47)](https://camo.githubusercontent.com/28d4af06c43652886d4de4bddbfe39528f510bdc6015832187beac7b926df6cb/687474703a2f2f676c6964652e6e616d652f646f63732f7a66632d7472616e736974696f6e2f6d666d2f312e504e47)

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

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

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

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

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

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

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

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

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

Решение
-------

[](#решение)

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

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

[![](https://camo.githubusercontent.com/61acd34cf8bff4b841190e502c5ac76b47187d1b8f8fbbf19e41c84368a13a10/687474703a2f2f676c6964652e6e616d652f646f63732f7a66632d7472616e736974696f6e2f6d666d2f322e504e47)](https://camo.githubusercontent.com/61acd34cf8bff4b841190e502c5ac76b47187d1b8f8fbbf19e41c84368a13a10/687474703a2f2f676c6964652e6e616d652f646f63732f7a66632d7472616e736974696f6e2f6d666d2f322e504e47)

Класс наследуется от uglide\\DbFixtureManager\\ContainerAbstract:

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

```

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

```
  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 - это метод, который будет вызван автоматически для удаления поднятой фикстуры.

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

```
/**
 * 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;
            }
        }
    });

```

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

```
use uglide\DbFixtureManager\TestCase;

class BaseTestCase extends TestCase
{

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

}

```

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

Как использовать в тестах:

```

// 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
                )
        );
    }

```

Использование фикстур из контейнера

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

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

```
        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
	        )
	    );
	 }

```

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

```

	//  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'];
        // ....
    }

```

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

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

```
        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 раз на этапе создания метода, для подъема фикстуры
- тесты не захламляются большим количеством кода для поднятия фикстур и за счет этого мы получаем более чистые и понятные тесты
- фикстуры для БД каждого модуля собраны в одном месте и ими проще управлять
- получение динамически созданных фикстур

###  Health Score

25

—

LowBetter than 37% of packages

Maintenance20

Infrequent updates — may be unmaintained

Popularity14

Limited adoption so far

Community7

Small or concentrated contributor base

Maturity48

Maturing project, gaining track record

 Bus Factor1

Top contributor holds 100% of commits — single point of failure

How is this calculated?**Maintenance (25%)** — Last commit recency, latest release date, and issue-to-star ratio. Uses a 2-year decay window.

**Popularity (30%)** — Total and monthly downloads, GitHub stars, and forks. Logarithmic scaling prevents top-heavy scores.

**Community (15%)** — Contributors, dependents, forks, watchers, and maintainers. Measures real ecosystem engagement.

**Maturity (30%)** — Project age, version count, PHP version support, and release stability.

###  Release Activity

Cadence

Unknown

Total

1

Last Release

4779d ago

### Community

Maintainers

![](https://www.gravatar.com/avatar/337de11b3faebfb5c8165ca52039e7fee5d33e594e50b9cc4a7b81f8d1fed9bd?d=identicon)[uglide](/maintainers/uglide)

---

Top Contributors

[![uglide](https://avatars.githubusercontent.com/u/1655867?v=4)](https://github.com/uglide "uglide (8 commits)")

---

Tags

Fixturetestsdb

### Embed Badge

![Health badge](/badges/uglide-db-fixture-manager/health.svg)

```
[![Health](https://phpackages.com/badges/uglide-db-fixture-manager/health.svg)](https://phpackages.com/packages/uglide-db-fixture-manager)
```

###  Alternatives

[typo3/testing-framework

The TYPO3 testing framework provides base classes for unit, functional and acceptance testing.

675.0M774](/packages/typo3-testing-framework)[aik099/phpunit-mink

Library for using Mink in PHPUnit tests. Supports session sharing between tests in a test case.

72136.2k1](/packages/aik099-phpunit-mink)[phpunit/phpunit-dom-assertions

DOM assertions for PHPUnit

29343.5k11](/packages/phpunit-phpunit-dom-assertions)[lastzero/test-tools

Increases testing productivity by adding a service container and self-initializing fakes to PHPUnit

2244.3k13](/packages/lastzero-test-tools)

PHPackages © 2026

[Directory](/)[Categories](/categories)[Trending](/trending)[Changelog](/changelog)[Analyze](/analyze)
