Тестирование и globalFixture

Всё про тестирование в Yii 2.0
Ответить
oke11o
Сообщения: 5
Зарегистрирован: 2016.01.20, 15:36

Тестирование и globalFixture

Сообщение oke11o »

Здравствуйте.

Интересует вопрос правильности тестирования.

У меня есть n-ое кол-во тестов. Которые работают с n-ым кол-вом таблиц в базе данных. (1
Для таблиц я создал fixture. Но они заполняют таблицы 20 сек.
Когда я пишу Unit тесты - fixture заполняют базу для каждого теста. На одно заполнение уходит 20сек. То есть для 5 тестов база заполняется 100сек.

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

Сейчас я в одном классе теста пишу только один публичный метод для теста. А в нем вызываю приватные методы-подтесты.

В принципе, это метод рабочий. Но я хотел бы использовать глобальные фикстуры, которые бы заполняли базу только один раз, при инициализации приложения.

Думал, что это можно сделать через метод glogalFixture().

Но это не сработало.

Добавил вот такой метод в класс теста, но в этом случае база не заполнилась.

Код: Выделить всё

    public function globalFixture()
    {
        return ArrayHelper::merge(
            parent::globalFixtures(),
            [
                'users' => UsersFixture::className(),
                ...
            ]
        );
    }
Так же пробовал учтановить через конфиг. Также не заполняется база.

Код: Выделить всё

return [
    'language' => 'en-US',
    'controllerMap' => [
        'fixture' => [
            'class' => 'yii\faker\FixtureController',
            'fixtureDataPath' => '@tests/codeception/fixtures',
            'templatePath' => '@tests/codeception/templates',
            'namespace' => 'tests\codeception\fixtures',
            'globalFixtures' => [
                'tests\codeception\fixtures\UsersFixture',
                'tests\codeception\fixtures\UsersRolesFixture',
                ...
            ],
        ],
    ],
    'components' => [
        'db' => [
            'dsn' => 'mysql:host=localhost;dbname=taskmanager_test',
        ],
        'mailer' => [
            'useFileTransport' => true,
        ],
        'urlManager' => [
            'showScriptName' => true,
        ],
    ],
];
Подскажите, как можно заполнять базу только один раз при запуске приложения?

PS:
при использовании метода public function fixtures()  база заполняется данными.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

зачем вам 1 раз?это не валидно, при запуске теста вам надо быть уверенным в данных в хранилищах
у вас 1 тест должен тестировать 1 сущность, точнее ее методы (апи) и логически сложные части, вот вам и надо залоадить всего 1 фикстуру, после теста она анлоадится

глобальные попробуйте посмотреть в _data/dump.sql
oke11o
Сообщения: 5
Зарегистрирован: 2016.01.20, 15:36

Re: Тестирование и globalFixture

Сообщение oke11o »

Да, мне надо быть уверенным, что тестовая база содержить те данные, которые мне нужны. Поэтому я и использую фикстуры.
Да, один тест проверяет 1 метод 1 модели.

Но вопрос все равно остается.
У меня 1 модель работает с несколькими связанными таблицами. Например, блог и его посты.
Если мне надо проверить 10 методов модели, я должен написать 10 тестов (минимум). Даже если эта модель работает только с одной базой, то все равно перед каждым тестом срабатывают фикстуры, и получается, что даже эта одна таблица будет заполнена одними и теми же данными 10 раз. А если тестов 500?

Поэтому мне и нужно, чтобы база заполнялась полностью перед запуском тестов, чтобы быть уверенным в достоверности данных в базе. Но только один раз. А если мне нужно проверить создание и обновление данных, я переопределяю фикстуры.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

The fixtures listed in the fixtures() method will be automatically loaded before running every test method in the test case and unloaded after finishing every test method.
(https://github.com/yiisoft/yii2/blob/ma ... ixtures.md)

если вам это создает проблемы, юзайте sqllite бд для тестов, вообще не понимаю зачем вы в тесте покрываете доменный слой логики:
>Даже если эта модель работает только с одной базой
зачем тестировать то, что протестировали до нас https://github.com/yiisoft/yii2/tree/ma ... amework/db
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

вот дальше там читайте по ссылке
The fixtures described above are mainly used by individual test cases. In most cases, you also need some global fixtures that are applied to ALL or many test cases. An example is [[yii\test\InitDbFixture]] which does two things:
(с) https://github.com/yiisoft/yii2/blob/ma ... l-fixtures
rumasterov
Сообщения: 17
Зарегистрирован: 2013.01.18, 19:00

Re: Тестирование и globalFixture

Сообщение rumasterov »

lynicidn писал(а): >Даже если эта модель работает только с одной базой
зачем тестировать то, что протестировали до нас https://github.com/yiisoft/yii2/tree/ma ... amework/db
А сохранение модели протестировать например? И убедиться что все поля заполнились в базе данных как нужно? Т.е. скорее подобные тесты с базой тестируют не столько сами методы фрейморка (это действительно не нужно) сколько схему базы данных. Я например еще тестирую связи, чтобы быть уверенным что у меня создана таблица для связи и что связь работает (я всё правильно объявил в модели).

У меня есть DbModelTest и ModelTest - в первом тесте тестируются методы для которых нужны данные в базе, а во втором я тестирую методы для которых данные в базе не нужны, передаю в методы параметры и проверяю результат.

lynicidn, Вы так не делаете? Поделитесь опытом, интересно кто как тестирует модели :)
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

rumasterov писал(а):
lynicidn писал(а): >Даже если эта модель работает только с одной базой
зачем тестировать то, что протестировали до нас https://github.com/yiisoft/yii2/tree/ma ... amework/db
А сохранение модели протестировать например? И убедиться что все поля заполнились в базе данных как нужно? Т.е. скорее подобные тесты с базой тестируют не столько сами методы фрейморка (это действительно не нужно) сколько схему базы данных. Я например еще тестирую связи, чтобы быть уверенным что у меня создана таблица для связи и что связь работает (я всё правильно объявил в модели).

У меня есть DbModelTest и ModelTest - в первом тесте тестируются методы для которых нужны данные в базе, а во втором я тестирую методы для которых данные в базе не нужны, передаю в методы параметры и проверяю результат.

lynicidn, Вы так не делаете? Поделитесь опытом, интересно кто как тестирует модели :)
вот смотрите, разработчики запилили тесты, что на подачу аттрибутов в ар те записываются в бд, что они выбираются, что и джоин с ними работает

Зачем вам тестировать, то, что отвечает за запись - это уже реализовано, юзает внутри свой коннекшен и все. Вы тестируйте свою логику. Если говорить о юнитах, то каждого метода в отдельности, и либо зависимымми их делать @depends, либо мокать "задевающие", к примеру юзаю метод1, а он вызывает метод2, вот надо мокнуть метод2 либо у метода1 поставить, что его тестирование зависит от метода2
rumasterov
Сообщения: 17
Зарегистрирован: 2013.01.18, 19:00

Re: Тестирование и globalFixture

Сообщение rumasterov »

lynicidn писал(а):
rumasterov писал(а):
lynicidn писал(а): >Даже если эта модель работает только с одной базой
зачем тестировать то, что протестировали до нас https://github.com/yiisoft/yii2/tree/ma ... amework/db
А сохранение модели протестировать например? И убедиться что все поля заполнились в базе данных как нужно? Т.е. скорее подобные тесты с базой тестируют не столько сами методы фрейморка (это действительно не нужно) сколько схему базы данных. Я например еще тестирую связи, чтобы быть уверенным что у меня создана таблица для связи и что связь работает (я всё правильно объявил в модели).

У меня есть DbModelTest и ModelTest - в первом тесте тестируются методы для которых нужны данные в базе, а во втором я тестирую методы для которых данные в базе не нужны, передаю в методы параметры и проверяю результат.

lynicidn, Вы так не делаете? Поделитесь опытом, интересно кто как тестирует модели :)
вот смотрите, разработчики запилили тесты, что на подачу аттрибутов в ар те записываются в бд, что они выбираются, что и джоин с ними работает

Зачем вам тестировать, то, что отвечает за запись - это уже реализовано, юзает внутри свой коннекшен и все. Вы тестируйте свою логику. Если говорить о юнитах, то каждого метода в отдельности, и либо зависимымми их делать @depends, либо мокать "задевающие", к примеру юзаю метод1, а он вызывает метод2, вот надо мокнуть метод2 либо у метода1 поставить, что его тестирование зависит от метода2
Вот например мы не покрыли тестами метод модели hasAuthor(), который для поста блога возвращает связь с автором поста из другой таблицы, и в таблице с постами переименовали поле author_id или удалили :) И без теста когда мы узнаем что у нас нарушена структура базы данных и связь перестала работать? В общем, я выше имел ввиду что тесты моделей которые выбирают тестовые данные из базы данных или сохраняют данные в нее, используются больше для того чтобы убедиться что база данных содержит нужную структуру.

Или например в моделе правило валидации на название поста в 100 символов, а в базе данных стоит ограничение для этого поля в 50 символов, как без теста который сохранит модель в базу об этом узнать?

Понятно, что всякие findAll() и прочие методы выборки я не тестирую, это протестировали разработчики yii, но сохранение модели и связи тестирую.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

если у вас связи неверные то скорее всего будет ошибка, тестировать все кейсы где возможна опечатка - глупо, а как работают addRelatedRecord, getRelated, и прочие yii\db\ARI плюшки уже нет смысла
тестируй логику поведений, валидаторов, что все что от new или instantiate до save или при желании можно углубиться
тестировать протектед методы можно так

Код: Выделить всё

  /**
     * @group static
     * @covers Config::removeEmptyAttributes
     */
    public function testRemoveEmptyAttributes()
    {
        $method = new ReflectionMethod(Config::className(), 'removeEmptyAttributes');
        $method->setAccessible(true);
        $this->specify('::removeEmptyAttributes', function() use ($method) {
            $result = $method->invoke(null, ['null' => null, 'empty' => '', 'integer' => 1, 'string' => '123']);
            verify($result)->equals(['integer' => 1, 'string' => '123']);
        });
    }
 
можно же логику подкладывать как тебе угодно

Код: Выделить всё

/**
     * @depend setRecord
     * @group record
     */
    public function testPush()
    {
        $record = $this->getMock(ActiveRecord::className(), ['setAttributes', 'safeAttributes']);
        $record->expects($this->any())->method('safeAttributes')->willReturn(['a']);

        $entity = $this->getMock(Entity::className(), ['pushAttributes'], [['record' => $record]]);
        $entity->expects($this->any())->method('pushAttributes')->willReturn(['a' => 'a', 'b' => 'b']);

        $record->expects($this->exactly(4))->method('setAttributes')->with(['a' => 'a'], true);
        $entity->push();
        $entity->push(['a', 'c']);
        $entity->push(['a']);
        $entity->push('a');
    }
 
oke11o
Сообщения: 5
Зарегистрирован: 2016.01.20, 15:36

Re: Тестирование и globalFixture

Сообщение oke11o »

lynicidn писал(а): глобальные попробуйте посмотреть в _data/dump.sql
Да, попробую так.
rumasterov писал(а): А сохранение модели протестировать например?
Сохранение моделей стоит тестировать, если переопределяется метод beforeSave() модели, который может вернуть false, и тогда сохранение не пройдет, даже при валидной моделе.
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

oke11o писал(а):
lynicidn писал(а): глобальные попробуйте посмотреть в _data/dump.sql
Да, попробую так.
rumasterov писал(а): А сохранение модели протестировать например?
Сохранение моделей стоит тестировать, если переопределяется метод beforeSave() модели, который может вернуть false, и тогда сохранение не пройдет, даже при валидной моделе.
надо тестировать метод beforeSave, в юнит тесте, что он возвращает тру когда ожидаем и фальш когда тоже ждет провала
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

если есть события, то их тестировать тоже отдельно.

То что вы пишите это функциональные тесты, а в функциональных можно тестировать контроллеры, ибо тестировать само сохранение модели, это накладно и пересекающийся, так сказать участок логики, с acceptance и functional
lynicidn
Сообщения: 2222
Зарегистрирован: 2014.05.24, 15:12

Re: Тестирование и globalFixture

Сообщение lynicidn »

lynicidn писал(а):
oke11o писал(а):
lynicidn писал(а): глобальные попробуйте посмотреть в _data/dump.sql
Да, попробую так.
rumasterov писал(а): А сохранение модели протестировать например?
Сохранение моделей стоит тестировать, если переопределяется метод beforeSave() модели, который может вернуть false, и тогда сохранение не пройдет, даже при валидной моделе.
надо тестировать метод beforeSave, в юнит тесте, что он возвращает тру когда ожидаем и фальш когда тоже ждет провала
если есть события, детачиим их просто и тестируем голый бефор сейф,, если имеет смысл
oke11o
Сообщения: 5
Зарегистрирован: 2016.01.20, 15:36

Re: Тестирование и globalFixture

Сообщение oke11o »

Вопрос остается открытым.
Я создал дамп базы. Добавил его в _data/dump.sql.
Но тесты продолжают выполнятся по 20 сек. То есть 1 тест выполняется 20 сек. 2 теста - 40сек и тд. Такое же время как будто я указываю fixture.
Мне нужно протестировать именно выборки. Так как делается сложный запрос для подсчета статистики. И нужно быть уверенным, что статистика считается верно.
Сейчас я вручную загружаю дамп. И убрал fixture и _data/dump.sql
Есть ли более верный способ?
rumasterov
Сообщения: 17
Зарегистрирован: 2013.01.18, 19:00

Re: Тестирование и globalFixture

Сообщение rumasterov »

oke11o писал(а):Вопрос остается открытым.
Я создал дамп базы. Добавил его в _data/dump.sql.
Но тесты продолжают выполнятся по 20 сек. То есть 1 тест выполняется 20 сек. 2 теста - 40сек и тд. Такое же время как будто я указываю fixture.
Мне нужно протестировать именно выборки. Так как делается сложный запрос для подсчета статистики. И нужно быть уверенным, что статистика считается верно.
Сейчас я вручную загружаю дамп. И убрал fixture и _data/dump.sql
Есть ли более верный способ?
http://codeception.com/docs/modules/Db#Config
cleanup: true - whether the dump should be reloaded after each test
Пробовали этот параметр? Он не будет после каждого теста базу очищать (перезаливать) если установить false, но это не совсем подходит конечно если тесты вносят изменения в базу.
Последний раз редактировалось rumasterov 2016.01.22, 15:19, всего редактировалось 1 раз.
oke11o
Сообщения: 5
Зарегистрирован: 2016.01.20, 15:36

Re: Тестирование и globalFixture

Сообщение oke11o »

rumasterov писал(а):
http://codeception.com/docs/modules/Db#Config

Код: Выделить всё

cleanup: true - whether the dump should be reloaded after each test
Пробовали этот параметр? Он не будет после каждого теста базу очищать если установить false, но это не совсем подходит конечно если тесты вносят изменения в базу.
Точно!!! Спасибо! Сейчас все тесты выполняются 20 сек.
Явно какая-то проблема с загрузкой дампа. Надо разобраться.
Ответить