Surf-vcr is a testing middleware for the Surf HTTP client library. Surf-vcr records your client's HTTP sessions with a server to later mock the server's HTTP responses, providing deterministic testing of your clients.
The high-level design is based on VCR for Ruby.
Source code is available on SourceHut and Github. Patches may be sent via either service, but the CI is running on SourceHut.
Surf-vcr records HTTP sessions to a YAML file so you can review and modify (or even create) the requests and responses manually. You can then inject the pre-recorded responses into your client sessions.
You'll typically be using surf-vcr as a development dependency, so add it as such via Cargo:
cargo add -D surf-vcr
Or add it to your Cargo.toml
file manually:
[dev-dependencies]
surf-vcr = "0.2.0"
Either in your application or the relevant test, register the middleware with
your application in Record
mode. You will connect to a functioning server and
record all requests and responses to a file. You can safely replay and record
multiple HTTP sessions (tests) with the same file concurrently.
Surf-vcr must be registered after any other middleware that modifies the
Request
or Response
; otherwise it will not see their modifications and
cannot record them.
I have found it useful to use a function in my application to create the Surf client with my middleware, then call that function in my tests as well so I know my test client and application client are identical:
fn create_surf_client() -> surf::Client {
let session = MySessionMiddleware::new();
surf::Client::new()
.with(session)
}
#[cfg(test)]
mod tests {
use super::*;
use async_std::task;
use surf_vcr::{VcrError, VcrMiddleware, VcrMode};
async fn create_test_client(mode: VcrMode, cassette: &'static str)
-> std::result::Result<surf::Client, VcrError>
{
let client = create_surf_client()
.with(VcrMiddleware::new(mode, cassette).await?);
Ok(client)
}
#[async_std::test]
async fn test_example_request() {
let client = create_test_client(
mode::VcrMode::Record,
"sessions/my-session.yml"
).await.unwrap();
let req = surf::get("https://www.example.com")
.insert_header("X-my-header", "stuff");
let mut res = client.send(req).await.unwrap();
assert_eq!(res.status(), surf::StatusCode::Ok);
let content = res.body_string().await.unwrap();
assert!(content.contains("illustrative examples"));
}
}
Take a look at the docs or the simple example for more.
To mock the server's responses simply change VcrMode::Record
to
VcrMode::Replay
and re-run your tests. Surf-vcr will look up each request
made, intercept it, and return the saved response.
You can modify data before writing to your cassette files. This is useful while working with sensitive or dynamic data.
VcrMiddleware::new(VcrMode::Record, path).await?
.with_modify_request(|req| {
req.headers
.entry("session-key".into())
.and_modify(|val| *val = vec!["...(erased)...".into()]);
})
.with_modify_response(|res| {
res.headers
.entry("Set-Cookie".into())
.and_modify(|val| *val = vec!["...(erased)...".into()]);
});
All source code is licensed under the terms of the MPL 2.0 license.
Patches and pull requests are welcome. For major features or breaking changes, please open a ticket or start a discussion first so we can discuss what you would like to do.