29 окт. 2018 г.
В предыдущей статье мы насторили окружение для тестов. В этой статье попробуем писать сами тесты.
У нас есть модуль. Пусть это будет личный кабинет. Но в отличии от стандартного модуля magento, это будет rest api. К нему можно будет подключить свой frontend.
Тесты будут лежать в папке Tests Здесь будут 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 не очень подошел для этих целей.
К сожалению не завелось у меня. По-идее, должно работать, но не работает.
$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 данные, ответ от внешнего сервиса). Для временного хранения даных можно испошльзовать статический массив.
В процессе написания тестов возникали некоторые другие проблемы. Например нередко возникает ситуация, что в тестовом окружении и в нормальном режиме один и тот же код работает по-разному. Часто это возникает из-за кэширования, иногда по другим причинам. Также у меня возникала проблема с очень долгим запуском тестов. На этом пока все. Спасибо за внимание!