Your SDK integration already passes a canned completion test. The next lap is proving that the application behaves correctly when the response is incomplete, retried, streamed, or structurally unexpected. Build tests around the boundary you actually ship: your request builder, the SDK, its HTTP transport, and your response adapter.
Mock the transport, not the completion method
Replacing the SDK’s completion method with a fake object skips serialization, headers, endpoint construction, and response parsing. Keep the real SDK client and replace its network transport instead. For a Python OpenAI-compatible integration, an HTTPX MockTransport handler can inspect the outgoing request and return a controlled HTTP response.
Assert the request method, path, authorization header, model identifier, and decoded JSON body. Check absent fields as carefully as present ones: an omitted option and an explicit null can produce different upstream behavior. Avoid asserting raw JSON byte order unless your integration signs those exact bytes.
SwiftRelay fits this setup naturally because OpenAI-compatible SDKs use https://api.fastapirelay.com/v1 as their base URL. Assert that a chat completions request reaches /v1/chat/completions, without accidentally producing /v1/v1. Use a dummy credential in offline tests and reject unexpected destinations inside the mock handler.
Make fixtures expose adapter assumptions
A useful fixture is not merely valid JSON. It should exercise the fields your application consumes while preserving the response envelope the SDK expects. Start from a sanitized response captured from the endpoint you support, then create focused variations.
- Empty choices: Verify that your adapter reports an unusable response rather than raising an accidental indexing exception.
- Tool-call output: Return tool calls without ordinary text and confirm that the application dispatches them instead of displaying an empty answer.
- Length-limited output: Preserve the finish reason and prevent truncated content from being treated as a complete structured result.
- Missing usage: Make accounting explicitly unavailable rather than silently recording zero tokens.
- Unknown fields: Add extra metadata and verify that application-level parsing does not reject harmless additions.
Keep each fixture’s purpose narrow. A single response containing every unusual condition makes failures difficult to diagnose and encourages assertions that accidentally depend on unrelated fields.
Assign retry ownership before injecting failures
SDK retries and application retries can multiply requests. For ordinary error-mapping tests, disable SDK retries where supported so one injected failure produces one observable result. In dedicated retry tests, enable the intended policy and have the transport consume a scripted sequence of responses.
For example, return a rate-limit response followed by a successful completion. Assert the number of attempts, the final result, and whether your wrapper preserves useful error context. Test authentication failures separately and verify that they are not repeatedly retried. If your application owns backoff, inject its clock or sleeper rather than waiting in the test.
Do not assume a timeout means the upstream operation never happened. For workflows that execute tools or write records, test that repeated delivery cannot repeat the business action. Tie deduplication to your application’s operation identity, not to generated answer text.
Exercise streaming as a sequence of events
A single buffered success response cannot validate streaming behavior. Feed server-sent events through the SDK’s streaming interface, using fixtures that split text and tool arguments across multiple events. Assert that your adapter reconstructs the output correctly and dispatches tools only after their arguments are complete.
Add an interrupted stream after partial output, an explicit terminal event, and a consumer cancellation. Verify that incomplete content stays marked incomplete and that the response is closed. Transport mocks do not reproduce every network behavior; use a local test server when socket disconnects or incremental delivery are the behavior under test.
Keep a live contract check outside the mock suite
Mocks prove consistency with your fixtures, not compatibility with today’s service. Maintain a small, separately triggered live check against the configured endpoint. Validate authentication, request acceptance, response parsing, and one application invariant without asserting exact generated wording.
Sign up for SwiftRelay when you are ready to run that live check, keeping credentials outside fixtures and logs. The green light is a deterministic offline suite plus a narrow live contract check—not a perfect imitation of every possible model response.