Test your code without a network

PHP

Use the test double the SDK ships with to queue the answers of the API and to check the requests your code sent.

4 min read

The SDK ships with a test double of its HTTP client. A test queues the answers the API would give, runs your code against a real SDK, and reads back the requests the SDK sent. No request leaves the process, and any non-empty text serves as the key.

The double is FakeHttpClient, in the namespace Slen\Sdk\Testing: a PSR-18 client.

Write a test

1. Queue an answer

Create the double and queue the answer of the API: a status and a body, as the API sends them. The body of a successful answer is wrapped in data.

PHP
use Slen\Sdk\Testing\FakeHttpClient;

$http = (new FakeHttpClient())->pushJson(200, ['data' => [
    'execution_id' => '74438200973594700',
    'status' => 'completed',
    'operation' => 'generate_email',
    'output' => ['content' => 'Hi Ada, just checking in on the proposal I sent last week.'],
    'error' => null,
    'error_code' => null,
    'error_message' => null,
    'cost' => ['estimated' => '0.00412500', 'actual' => null],
    'cache' => ['hit' => false, 'cached_at' => null],
    'replayed' => false,
    'waiting_on' => null,
    'trace_url' => '/v1/executions/74438200973594700',
]]);

2. Give the double to the SDK

The SDK is a real one. Only its HTTP client is replaced, so the test runs the same code your application runs.

PHP
use Slen\Sdk\SlenConfig;
use Slen\Sdk\SlenSdk;

$slen = SlenSdk::create(new SlenConfig(apiKey: 'key-for-tests', httpClient: $http));

The double is the httpClient of the config.

3. Run your code

PHP
use Slen\Sdk\Modules\Operations\Options\ExecuteOptions;

$execution = $slen->operations()->execute(
    'generate_email',
    ['messages' => [['role' => 'user', 'content' => 'Write a short follow-up email.']]],
    new ExecuteOptions(idempotencyKey: 'order-42:email'),
);

4. Check what was sent

The double records every request: the method, the address, the headers and the body.

PHP
$sent = $http->lastRequest();

echo $execution->status->value, PHP_EOL;
echo $sent->getMethod(), ' ', $sent->getUri(), PHP_EOL;
echo $sent->getHeaderLine('Idempotency-Key'), PHP_EOL;
echo json_decode((string) $sent->getBody(), true)['operation'], PHP_EOL;

lastRequest() returns the last request and requests() all of them, as PSR-7 requests.

Answers are given in the order they were queued

Each request takes the next answer of the queue. Queue one answer for every request your code makes.

The double is strict. A request with no answer queued for it fails the test with a LogicException, and the request is still recorded. A double that forgave an extra request would hide the mistake it is there to catch — a call sent twice.

The SDK sends a request again after a 429, a 503 or no answer, as many times as retries says — Retries and timeouts. A test of such an answer queues one answer for every attempt, or sets retries to 0 — for the whole SDK, or in the options of the one call.

Test an error

Queue an error the same way: its status and the error envelope of the API. The SDK raises the error it raises for the real answer. Overview describes the envelope.

404 Not Found
{
  "error": {
    "code": "flow_not_found",
    "message": "No flow is bound to operation \"generate_email\"",
    "request_id": "0d3c1b9e-5a47-4f0e-9a36-2f6c8d1e7b42"
  }
}

pushException() queues an exception of the HTTP client in place of an answer. A network exception of PSR-18 plays a request that got no answer, and the SDK sends the request again after it: queue one for every attempt, and the SDK raises ConnectionException after the last.

Test the spans

RecordingSpanRecorder, given to the config as spanRecorder, keeps the spans of the test: spans() returns them all and last() the last one — Spans.

Where to go next