Автотесты в Magento 2, часть 2

29 окт. 2018 г.

В предыдущей статье мы насторили окружение для тестов. В этой статье попробуем писать сами тесты.

У нас есть модуль. Пусть это будет личный кабинет. Но в отличии от стандартного модуля magento, это будет rest api. К нему можно будет подключить свой frontend.

Тесты будут лежать в папке Tests Здесь будут Unit тесты, Интеграционные тесты, вспомагательный код и фикстуры.

Unit тесты

Здесь все относительно просто. Струтура папок повторяет структуру модуля. И для каждого класса есть тестовый класс.

В тесте мы создаем экземпляр тестируемого класса. И в качестве параметров передаем зависимости. Какие-то зависимости могут быть реальными. Для каких-то зависимостей мы передаем mock объекты.

Получить mock можно таким образом.

$this->getMockBuilder($className)
            ->disableOriginalConstructor()
            ->getMock();

Дальше можно добавить методы. Которые будут что-то возвращать. Примерно так:

$categoryService = $this->getMock(CategoryService::class);
$data = [1 => 'Filter 1', 2 => 'Filter 2'];
$categoryService->method('getFilters')->will($this->returnValue($data));

Интеграционные тесты

Здесь мы будем тестировать код в натуральной среде обитания. С помощью object manager получим тестируемый класс. В него уже подставлены все реальные зависимости.

$this->objectManager = Bootstrap::getObjectManager();
$this->customerAttributeService = $this->objectManager->get('CCXX\Profile\Service\CustomerAttributeService');

И просто вызываем те методы, которые хотим протестировать. Проверяем результат

$result = $this->customerAttributeService->getCustomAttribute(1,$attributeCode);
$this->assertEquals($expectedValue,$result);

Для загрузки данных в базу используем фикстуры. Внимание, т.к мы отключили очистку базы, то нам необходимо самостоятельно следить за состоянием данных. Придется самим решать, когда и какие фикстуры загружать. Теоретически возможен вариант с транзакцией. Перед началом теста открываем транзакцию. Затем проводим все действия и проверки. Затем откатываем транзакцию. И можно проводить следующие тесты.

Фикстуры

Это кастомное изобретение. Просто набор классов, который отвечает за загрузку или очистку конкретных таблиц Базы данных. Коробочный функционал magento не очень подошел для этих целей.

Mock для интеграционных тестов.

К сожалению не завелось у меня. По-идее, должно работать, но не работает.

$this->objectManager = Bootstrap::getObjectManager();
$this->objectManager->configure(
    ['preferences' => [CustomerAuthService::class => CustomerAuthServiceStub::class]]
);

В итоге приходится в самом классе добавлять проверку на тестовое окружение и менять поведение.

if($this->isIntegrationTestEnv()){
    return $this->getIntegrationTestParam('customer_id');
}

Можно сделать это в виде вспомогательного trait и просто подключать в определенных классах. Для этого нужно реализовать в trait методы setIntegrationTestEnv и isIntegrationTestEnv, которые будут устанавливать и возвращать значение констант.

Также можно реализовать методы setIntegrationTestParam и getIntegrationTestParam для передачи данных в тестируемый класс(прим, mock данные, ответ от внешнего сервиса). Для временного хранения даных можно испошльзовать статический массив.

В процессе написания тестов возникали некоторые другие проблемы. Например нередко возникает ситуация, что в тестовом окружении и в нормальном режиме один и тот же код работает по-разному. Часто это возникает из-за кэширования, иногда по другим причинам. Также у меня возникала проблема с очень долгим запуском тестов. На этом пока все. Спасибо за внимание!