Тестирование API контроллеров в Laravel
Очень часто приходится писать тесты для API различных приложений и поэтому за долгое время накопилась парочка приемов, которыми хотелось бы поделиться.
Подготовка
- При разработке API я придерживаюсь практики создания Single Action Controllers, т.е. один контроллер имеет лишь один экшен, если наглядно, то выглядит как то так
Controllers
- Users
- UpdateAction.php
- CreateAction.php
- IndexAction.php
- Profile
- UpdatePasswordAction.php
- ...
- News
- IndexAction.php
- MarkAsReadAction.php
- ...
...
Это позволяет мне легко ориентироваться в тех действиях, которые имее тот или иной раздел или модуль, а также не раздувать контроллеры. Плюс ко всему это удобно тестировать, т.к. стурктура тестов может повторять структуру экшенов
Controllers
- Users
- UpdateActionTest.php
- CreateActionTest.php
- IndexActionTest.php
- Profile
- UpdatePasswordActionTest.php
- ...
- News
- IndexActionTest.php
- MarkAsReadActionTest.php
- ...
...
2. Каждый экшен имеет свой уникальный Route name, который является единственным источником для генерации URL для конкретного Route.
Приступим к написанию тестов
Т.к. я использую Single Action Controllers, то каждый контроллер по сути представлен одним TestCase, поэтому для тестирования можно создать отдельный TestCase, который помогал бы упростить процесс покрытия функционала тестами. Я назвал его ActionTestCase
Данный тест кейс имеет единственный обязательный метод getRouteName, который должен возвращать название роута для которого пишем тест. Данное имя позволяет в реестре роутов найти подходящий по имени и получить все необходимые данные для выполнения запросов.
Вот пример тестирования регистрации пользователя
И пример для тестирования авторизованного пользователя
А теперь немного расскажу, что про методы. Для себя я выявил несколько методов, которые мне помогают упростить рутинную работу:
- Имя роута я прописываю всего один раз
- По названию роута я нахожу нужный Route и определяю тип запроса, его наличие, а также я могу получить middleware, которые используются и также протестировать их наличие.
- При выполении запросов мне не нужно каждый раз указывать URL
Методы:
assertRouteContainsMiddleware(…$names)
Проверка на наличие в роуте переданных middleware.
assertRouteHasExactMiddleware(…$names)
Проверка на то, что роут содержит только указанные middleware.
getRouteByName(): Route
Получение объекта текущего роута. Если роут не найдет, то тест будет помечен как fail
callRouteAction(array $data = [], array $parameters = [], array $headers = []): TestResponse
Выполнение запроса от неавторизованного пользователя.
$data — Request body
$paramenters — Route parameters
$headers — Request headers
callAuthorizedRouteAction(array $data = [], array $parameters = [], array $headers = [], array $scopes = []): TestResponse
Выполнение авторизованного запроса. В момент запроса создается рандомный пользователь и от него выполняется запрос
callAuthorizedByUserRouteAction(User $user, array $data = [], array $parameters = [], array $headers = [], array $scopes = []): TestResponse
Выполнение запроса от имени переданного пользователя.
Ну вот собственно и все. Этих методов достаточно для выполнения повседневных рутинных операций.
Надеюсь моя статья будет полезна и сподвигнет вас на написание своих велосипедов. Делитесь своим опытом в комментариях, будет интересно почитать!