Тестирование клиентов Guzzle

Guzzle предоставляет несколько инструментов, которые позволят вам легко издеваться над HTTP-уровнем без необходимости отправлять запросы через интернет.

  • Макет обработчика
  • Историческое промежуточное программное обеспечение
  • Веб-сервер Node.js для интеграционного тестирования

Mock Handler

При тестировании HTTP-клиентов часто требуется имитировать определенные сценарии, такие как возвращение успешного ответа, возвращение ошибки или возвращение определенных ответы в определенном порядке. Поскольку модульные тесты должны быть предсказуемыми, простыми быстро загружаться, попадание в реальный удаленный API - это запах теста.

Guzzle предоставляет имитационный обработчик, который можно использовать для выполнения HTTP-запросов с ответом или исключением, перемещая возвращаемые значения из очереди.

use GuzzleHttp\Client;
use GuzzleHttp\Handler\MockHandler;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Psr7\Request;
use GuzzleHttp\Exception\RequestException;

// Create a mock and queue two responses.
$mock = new MockHandler([
    new Response(200, ['X-Foo' => 'Bar'], 'Hello, World'),
    new Response(202, ['Content-Length' => 0]),
    new RequestException('Error Communicating with Server', new Request('GET', 'test'))
]);

$handlerStack = HandlerStack::create($mock);
$client = new Client(['handler' => $handlerStack]);

// The first request is intercepted with the first response.
$response = $client->request('GET', '/');
echo $response->getStatusCode();
//> 200
echo $response->getBody();
//> Hello, World
// The second request is intercepted with the second response.
echo $client->request('GET', '/')->getStatusCode();
//> 202

// Reset the queue and queue up a new response
$mock->reset();
$mock->append(new Response(201));

// As the mock was reset, the new response is the 201 CREATED,
// instead of the previously queued RequestException
echo $client->request('GET', '/')->getStatusCode();
//> 201

Когда в очереди больше нет ответов, а запрос отправлен, возникает OutOfBoundsException.

History Middleware

При использовании таких вещей, как Mock обработчик, вам часто нужно знать, отправлены ли запросы, которые вы ожидали отправить, были отправлены именно так, как вы задумали. В то время как имитатор обработчик отвечает имитированными ответами, промежуточное ПО истории поддерживает историю запросов, которые были отправлены клиентом.

use GuzzleHttp\Client;
use GuzzleHttp\HandlerStack;
use GuzzleHttp\Middleware;

$container = [];
$history = Middleware::history($container);

$handlerStack = HandlerStack::create();
// or $handlerStack = HandlerStack::create($mock); if using the Mock handler.

// Add the history middleware to the handler stack.
$handlerStack->push($history);

$client = new Client(['handler' => $handlerStack]);

$client->request('GET', 'http://httpbin.org/get');
$client->request('HEAD', 'http://httpbin.org/get');

// Count the number of transactions
echo count($container);
//> 2

// Iterate over the requests and responses
foreach ($container as $transaction) {
    echo $transaction['request']->getMethod();
    //> GET, HEAD
    if ($transaction['response']) {
        echo $transaction['response']->getStatusCode();
        //> 200, 200
    } elseif ($transaction['error']) {
        echo $transaction['error'];
        //> exception
    }
    var_dump($transaction['options']);
    //> dumps the request options of the sent request.
}

Тестовый веб-сервер

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

  • Тесты более надежны
  • Тесты не требуют подключения к сети
  • Тесты не имеют внешних зависимостей

Использование тестового сервера

Предупреждение

Следующая функциональность предоставляется для того, чтобы помочь разработчикам Guzzle разрабатывать HTTP-обработчики. Не обещана обратная совместимость когда речь идет о тестовом сервере node.js или GuzzleHttp\Tests\Server класс. Если вы используете тестовый сервер или класс Server вне класса guzzlehttp/guzzle, то вам нужно будет настроить автозагрузку и обеспечить запуск веб-сервера вручную.

Подсказка

Вам практически никогда не понадобится использовать этот тестовый веб-сервер. Вы должны только использовать его при разработке HTTP-обработчиков. Тестовый веб-сервер не нужен для имитации запросов. Для этого, пожалуйста, используйте Mock handler and history middleware.

Guzzle поставляется с тестовым сервером node.js, который принимает запросы и возвращает ответы из очереди. Тестовый сервер предоставляет простой API, который используется для регистрации ответов и проверки полученных запросов.

Любая операция над объектом Server будет гарантировать, что сервер запущен и будет ждать, пока он не сможет принимать запросы, прежде чем возврата.

GuzzleHttp\Tests\Server предоставляет статический интерфейс к тестовому серверу. Вы можете поставить в очередь HTTP-ответ или массив ответов, вызвав команду Server::enqueue(). Этот метод принимает массив из Psr\Http\Message\ResponseInterface и Exception объектов.

use GuzzleHttp\Client;
use GuzzleHttp\Psr7\Response;
use GuzzleHttp\Tests\Server;

// Start the server and queue a response
Server::enqueue([
    new Response(200, ['Content-Length' => 0])
]);

$client = new Client(['base_uri' => Server::$url]);
echo $client->request('GET', '/foo')->getStatusCode();
// 200

Когда ответ ставится в очередь на тестовом сервере, тестовый сервер удаляет все ранее поставленные в очередь ответы. По мере получения сервером запросов ответы, поставленные в очередь снимаются с очереди и возвращаются к запросу. Когда очередь пуста, сервер вернет ответ 500.

Вы можете просмотреть запросы, которые получил сервер, вызвав Server::received().

foreach (Server::received() as $response) {
    echo $response->getStatusCode();
}

Вы можете очистить список полученных запросов от веб-сервера с помощью метода Server::flush().

Server::flush();
echo count(Server::received());
// 0