Rust testing
Test your integration without API calls using the Rust SDK. The mock is behind the testing feature, so enable it for tests only:
[dev-dependencies]
calmlens = { version = "0.1", features = ["testing"] }Mock client
MockClient answers requests from a queue and records them. It runs the real client's validation, request encoding, retries and error handling, and creates no HTTP client, so you can use it inside any async runtime.
use calmlens::{models::*, testing::MockClient};
#[tokio::test]
async fn reports_timeouts() -> calmlens::Result<()> {
let mock = MockClient::new()?;
mock.enqueue_timeout();
let error = mock.events().list(ListEvents::default()).await.unwrap_err();
assert!(error.is_timeout());
let request = mock.last_request().unwrap();
assert_eq!(request.path, "/v1/projects/project-1/events");
Ok(())
}Queue responses with:
| Method | Queues |
|---|---|
enqueue(status, model) | A JSON response from a model or serde_json::Value |
enqueue_api_error(code, message) | The API's error for code, with the HTTP status the API uses for it |
enqueue_response(MockResponse) | A response with headers, such as a CDN response with content-type or a 429 with retry-after |
enqueue_raw(status, bytes) | A raw body |
enqueue_timeout(), enqueue_transport_error(message), enqueue_error(error) | A failure |
requests() and last_request() return the captured requests with their method, url, path, decoded query (query_param(name)), headers (header(name)), body and json(). Streamed uploads are captured too. An empty queue fails with sdk/transport-error without making network calls. Mocks don't classify content or keep backend state.
MockClient::new() turns retries off, so each call uses one queued response. To test retries, build the mock like a real client: MockClient::from_builder(Client::builder(key, project).max_retries(2)).
Code that owns its client
When the code under test takes a Client, pass it mock.client(). The returned client answers from the same queue and records its requests in the same log. With the blocking feature, mock.blocking()? returns a blocking::Client wired to the same queue.
use calmlens::{models::*, testing::MockClient, Client};
async fn moderate_bio(client: Client, bio: &str) -> calmlens::Result<Asset> {
client.assets().moderate(SubmitAsset::text(bio)).await
}
#[tokio::test]
async fn approves_bios() -> calmlens::Result<()> {
let mock = MockClient::new()?;
mock.enqueue(200, Asset::new("asset-1", AssetStatus::Approved));
let asset = moderate_bio(mock.client(), "Hello").await?;
assert_eq!(asset.id, "asset-1");
assert_eq!(mock.requests().len(), 1);
Ok(())
}Webhook handlers
Sign test deliveries with create_webhook_signature_header, and build a delivery body from an event with WebhookEventPayload::from_event, the same conversion CalmLens applies before sending.