Как протестировать API-запрос сервис-клиента?
Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Подход к тестированию API-запросов сервис-клиента
Тестирование API-запросов сервис-клиента — критически важная задача для обеспечения надежности интеграций с внешними сервисами. Я использую многоуровневый подход, сочетающий различные типы тестов для максимального покрытия.
Основные стратегии тестирования
1. Юнит-тестирование с моками и стабами На этом уровне мы изолируем сервис-клиент от реального API, подменяя HTTP-слой:
<?php
use PHPUnit\Framework\TestCase;
use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
class ApiClientTest extends TestCase
{
public function testGetUserData()
{
// Создаем мок-ответ
$mockResponse = json_encode(['id' => 1, 'name' => 'John']);
// Настраиваем мок-клиент Guzzle
$mockHandler = new MockHandler([
new Response(200, ['Content-Type' => 'application/json'], $mockResponse)
]);
$handlerStack = HandlerStack::create($mockHandler);
$httpClient = new Client(['handler' => $handlerStack]);
// Создаем тестируемый клиент с мок-зависимостью
$apiClient = new UserApiClient($httpClient);
$result = $apiClient->getUser(1);
$this->assertEquals('John', $result['name']);
$this->assertEquals(200, $apiClient->getLastStatusCode());
}
}
2. Интеграционные тесты с тестовым окружением Для проверки реального взаимодействия с API используем тестовое окружение:
<?php
class UserApiClientIntegrationTest extends TestCase
{
private $apiClient;
protected function setUp(): void
{
// Используем тестовые учетные данные
$baseUri = getenv('TEST_API_BASE_URL');
$apiKey = getenv('TEST_API_KEY');
$this->apiClient = new UserApiClient($baseUri, $apiKey);
}
public function testRealApiConnection()
{
// Тест с реальным, но тестовым API
$response = $this->apiClient->getUser('test_user_123');
$this->assertArrayHasKey('id', $response);
$this->assertNotEmpty($response['email'] ?? null);
}
}
Ключевые аспекты для тестирования
Покрытие различных сценариев:
- Успешные запросы (200, 201)
- Ошибки клиента (4xx: 400, 401, 403, 404, 429)
- Ошибки сервера (5xx: 500, 502, 503)
- Таймауты и сетевые проблемы
- Невалидные JSON-ответы
- Ответы с неожиданной структурой
Тестирование повторных попыток (retry logic):
<?php
public function testRetryOnServerError()
{
$mockHandler = new MockHandler([
new Response(500), // Первый запрос падает
new Response(500), // Второй запрос падает
new Response(200, [], json_encode(['status' => 'ok'])) // Третий успешен
]);
$client = new Client([
'handler' => HandlerStack::create($mockHandler),
'retries' => 3
]);
$apiClient = new UserApiClient($client);
// Этот вызов должен выдержать 2 неудачи и добиться успеха
$result = $apiClient->getUser(1);
$this->assertEquals('ok', $result['status']);
}
Инструменты и библиотеки
Основной стек для PHP:
- PHPUnit — основной фреймворк для тестирования
- Guzzle MockHandler — для мокинга HTTP-запросов
- PHP-VCR — для записи и воспроизведения реальных API-запросов
- Mockery или Prophecy — для создания сложных мок-объектов
Практические рекомендации
- Используйте конфигурацию через окружение — отделяйте тестовые и продакшен-ключи API
- Создайте фабрику для клиента — упростите создание клиентов с разными конфигурациями
- Тестируйте edge cases — пустые ответы, максимально длинные поля, спецсимволы
- Версионируйте тестовые данные — синхронизируйте с изменениями в реальном API
- Измеряйте покрытие (code coverage) — стремитесь к 80%+ для критических методов
- Автоматизируйте в CI/CD — запускайте тесты при каждом коммите
Пример комплексного теста
<?php
class ApiClientComprehensiveTest extends TestCase
{
/**
* @dataProvider apiErrorProvider
*/
public function testErrorHandling($statusCode, $expectedException)
{
$mockHandler = new MockHandler([
new Response($statusCode)
]);
$this->expectException($expectedException);
$client = new UserApiClient(new Client([
'handler' => HandlerStack::create($mockHandler)
]));
$client->getUser(1);
}
public function apiErrorProvider(): array
{
return [
[400, BadRequestException::class],
[401, UnauthorizedException::class],
[403, ForbiddenException::class],
[404, NotFoundException::class],
[429, RateLimitException::class],
[500, ServerException::class],
];
}
}
Важность: Хорошо протестированный сервис-клиент предотвращает сбои в продакшене, уменьшает время отладки и повышает устойчивость приложения к внешним сбоям. Инвестиции в качественное тестирование API-клиентов многократно окупаются при масштабировании системы.