#laravel #rest #phpunit
#laravel #rest #phpunit
Вопрос:
Я пытаюсь протестировать Laravel REST API через phpunit. Во время тестирования вызовов REST я не могу изолировать тесты вызовов REST.
В Laravel я понимаю несколько вариантов, таких как использование черт DatabaseMigrations
, DatabaseRefresh
, DatabaseTransactions
. Но я не могу использовать их по следующим причинам:
DatabaseMigrations
: Приложение не имеет надлежащих миграций. Даже если бы это было так, это было бы довольно неэффективно.DatabaseRefresh
: То же, что и выше.DatabaseTransactions
. Проблема, которую я вижу, заключается в том, что вызов HTTP API — это совершенно другой процесс. Они не входят в одну транзакцию. Таким образом, тест, который вставляет данные для настройки тестового примера, не отображается HTTP-вызовом. Кроме того, если данные вставляются с помощью HTTP-вызовов, like будут видны другим тестам.
Я не могу писать модульные тесты без вызова HTTP; приложение не написано таким образом. Весь код Routes
включен или Controller
не может быть протестирован иным образом.
Комментарии:
1. Если у вас нет запланированной рабочей базы данных, структурированной таким образом, который не соответствует sqlite, тогда хорошим шагом будет работа над определением правильных миграций. Затем вы можете использовать sqlite в памяти для тестирования с помощью DatabaseMigrations или RefreshDatabase, и тесты все равно будут довольно быстрыми — просто мысль
2. @Donkarnash Будет довольно сложно создать миграции всей схемы, хотя и не невозможно. Я попробую, как только найду инструмент, который делает это автоматически, я имею в виду взять sql и преобразовать его в Laravel Migration / Seeder. Однако я все еще ищу решение, которое, возможно, касается транзакций. Возможно, это путь наименьшего сопротивления.
3. Можете ли вы объяснить, почему API вызывает совершенно другую транзакцию? Вы пытались написать простой тестовый пример? если да, можете ли вы показать нам код?
4. Я думаю, что у вас есть неправильное представление о том, что вы собираетесь вызывать API с помощью HTTP-запроса по сети. В Laravel для этого есть HTTP-тесты, см. Документы по адресу laravel.com/docs/8.x/http-tests для получения дополнительной информации. Вся идея тестирования заключается в том, что вы всегда используете фиктивные экземпляры. Как еще вы могли бы предотвратить запуск приложением реальных событий или запись в вашу базу данных разработчика или даже в производственную базу данных вместо тестовой базы данных?
Ответ №1:
я тестирую свои конечные точки с помощью функции json (я полагаю, что также есть методы POST и GET, но мне нужно передать данные и заголовки)
public function test_endpoint() {
$result = $this->json('POST', '/api', ['key' => 'data'], ['Header' => "Value"]);
}
у меня также есть модульные и функциональные тесты, но я использую это для тестирования конечной точки GraphQL.
Ответ №2:
Итак, в моем примере void
это означает, что наш метод ничего не возвращает. postJson
означает, что мы ожидаем JSON
ответа, либо мы можем сделать просто $this->post()
Вы можете выполнять вызовы, подобные этому
public function test_create_order() : void
{
$response = $this->postJson('/make-order',[
'foo' => 'bar',
'baz' => 'bat'
]);
// To make sure it is returning 201 created status code, or other code e.g. (200 OK)
$response->assertStatus(201);
// To make sure it is in your desired structure
$response->assertJsonStructure([
'id',
'foo',
'baz',
]);
// Check if response contains exactly that value, what we inserted
$this->assertEquals('bar', $response->json('data.foo'));
// Check that in the database created that record,
// param 1 is table name, param 2 is criteria to find that record
// e.g. ['id' => 1]
$this->assertDatabaseHas('orders', [
'foo' => 'bar'
]);
// Also there is other method assertDatabaseMissing, that works like above
// just in reverse logic, it is checking that there is no record with that criteria
}
Комментарии:
1. Удаление заказов из других тестов в тесте немного странно, вы можете
use DatabaseTransactions
оставить базу данных в нетронутом состоянии.