lukemathwalker/wiremock-rs

HTTP mocking to test Rust applications

wiremock provides HTTP mocking to perform black-box testing of Rust applications that

wiremock

.


wiremock provides HTTP mocking to perform black-box testing of Rust applications that interact with third-party APIs.

It provides mocking of HTTP responses using request matching and response templating.

The name wiremock is a reference to WireMock.Net, a .NET port of the original Wiremock from Java.

Documentation - Crates.io

Table of Contents

  1. How to install
  2. Getting started
  3. Matchers
  4. Spying
  5. Responses
  6. Test isolation
  7. Runtime compatibility
  8. Efficiency
  9. Prior art
  10. Future evolution
  11. Related projects
  12. License

How to install

Add wiremock to your development dependencies:

[dev-dependencies]
# ...
wiremock = "0.5"

If you are using cargo-edit, run

cargo add wiremock --dev

Getting started

use wiremock::{MockServer, Mock, ResponseTemplate};
use wiremock::matchers::{method, path};

#[async_std::main]
async fn main() {
    // Start a background HTTP server on a random local port
    let mock_server = MockServer::start().await;

    // Arrange the behaviour of the MockServer adding a Mock:
    // when it receives a GET request on '/hello' it will respond with a 200.
    Mock::given(method("GET"))
        .and(path("/hello"))
        .respond_with(ResponseTemplate::new(200))
        // Mounting the mock on the mock server - it's now effective!
        .mount(&mock_server)
        .await;

    // If we probe the MockServer using any HTTP client it behaves as expected.
    let status = surf::get(format!("{}/hello", &mock_server.uri()))
        .await
        .unwrap()
        .status();
    assert_eq!(status.as_u16(), 200);

    // If the request doesn't match any `Mock` mounted on our `MockServer` a 404 is returned.
    let status = surf::get(format!("{}/missing", &mock_server.uri()))
        .await
        .unwrap()
        .status();
    assert_eq!(status.as_u16(), 404);
}

Matchers

wiremock provides a set of matching strategies out of the box - check the matchers module for a complete list.

You can define your own matchers using the Match trait, as well as using Fn closures. Check Match's documentation for more details and examples.

Spying

wiremock empowers you to set expectations on the number of invocations to your Mocks - check the expect method for more details.

Expectations can be used to verify that a side-effect has (or has not) taken place!

Expectations are automatically verified during the shutdown of each MockServer instance, at the end of your test. A failed verification will trigger a panic. By default, no expectations are set on your Mocks.

Responses

wiremock lets you specify pre-determined responses using ResponseTemplate and respond_with.

You are also given the option to have Mocks return different responses based on the matched Request using the Respond trait. Check Respond's documentation for more details and examples.

Test isolation

Each instance of MockServer is fully isolated: start takes care of finding a random port available on your local machine which is assigned to the new MockServer.

To ensure full isolation and no cross-test interference, MockServers shouldn't be shared between tests. Instead, MockServers should be created in the test where they are used.

When a MockServer instance goes out of scope (e.g. the test finishes), the corresponding HTTP server running in the background is shut down to free up the port it was using.

Runtime compatibility

wiremock can be used (and it is tested to work) with both async_std and tokio as futures runtimes. If you encounter any compatibility bug, please open an issue on our GitHub repository.

Efficiency

wiremock maintains a pool of mock servers in the background to minimise the number of connections and the time spent starting up a new MockServer. Pooling reduces the likelihood of you having to tune your OS configurations (e.g. ulimit).

The pool is designed to be invisible: it makes your life easier and your tests faster. If you end up having to worry about it, it's a bug: open an issue!

Prior art

mockito and httpmock provide HTTP mocking for Rust.

Check the table below to see how wiremock compares to them across the following dimensions:

  • Test execution strategy (do tests have to be executed sequentially or can they be executed in parallel?);
  • How many APIs can I mock in a test?
  • Out-of-the-box request matchers;
  • Extensible request matching (i.e. you can define your own matchers);
  • Sync/Async API;
  • Spying (e.g. verify that a mock has/hasn't been called in a test);
  • Standalone mode (i.e. can I launch an HTTP mock server outside of a test suite?).
Test execution strategy How many APIs can I mock? Out-of-the-box request matchers Extensible request maching API Spying Standalone mode
mockito ❌ Sequential ❌ 1 Sync
httpmock ✔ Parallel ✔ Unbounded Async/Sync
wiremock ✔ Parallel ️ ✔ Unbounded Async

Future evolution

More request matchers can be added to those provided out-of-the-box to handle common usecases.

Related projects

  • stubr for mounting Wiremock json stubs in a MockServer. Also works as a cli.

License

Licensed under either of Apache License, Version 2.0 or MIT license at your option. Unless you explicitly state otherwise, any contribution intentionally submitted for inclusion in this crate by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.

Issues

Collection of the latest Issues

johannescpk

johannescpk

Comment Icon4

Thanks for wiremock! It seems that it's currently not possible to execute async code in the respond method or respond trait. It'd be useful to have it natively supported by wiremock.

Wasn't able to find a workaround, tried

but that's blocking the tokio runtime since the test runs as #[tokio::test].

sjud

sjud

Comment Icon2

Hello, I think having clearer failed verification messages would make debugging multiple chained .and(matcher) calls easier. For example: Mock::given(header_exists("X-Postmark-Server-Token")) .and(header("Content-Type", "application/json")) .and(path("/email")) .and(method("POST")) .and(SendEmailBodyMatcher) Fails with: thread 'email_client::tests::send_email_sends_the_expected_request' panicked at 'Verifications failed:

  • Mock #0. Expected range of matching incoming requests: == 1 Number of matched incoming requests: 0

As opposed to specifying which matcher in particular failed.

LukeMathWalker

LukeMathWalker

Comment Icon0

It should be possible to spin up an HTTPS mock server. This probably requires implementing some routine to generate a set of certificates on the fly which the HTTP client would then need to trust.

mre

mre

Comment Icon4

Hey,

thanks for the crate.

I'm building a link checker and I need a way to simulate a connect delay. Here's a little snippet to show what I tried:

get_checker is just a wrapper around reqwest.

This didn't work. It's obvious, in hindsight, because I was mixing up the response delay with a connect delay. Any way I could test that right now? Maybe there could be another parameter set_connect_delay for that?

Information - Updated Apr 08, 2022

Stars: 329
Forks: 40
Issues: 7

Rust bindings for libinjection

Add libinjection to dependencies of Cargo

Rust bindings for libinjection

Rust bindings for the C++ api of PyTorch

LIghtweight wrapper for pytorch eg libtorch in rust

Rust bindings for the C++ api of PyTorch

Rust leveldb bindings

Almost-complete bindings for leveldb for Rust

Rust leveldb bindings

rust-analyzer is a modular compiler frontend for the Rust language

It also contains some tips & tricks to help you be more productive when using rust-analyzer

rust-analyzer is a modular compiler frontend for the Rust language

Rust-Lightning is a Bitcoin Lightning library written in Rust

lightning, does not handle networking, persistence, or any other I/O

Rust-Lightning is a Bitcoin Lightning library written in Rust

Rust FUSE - Filesystem in Userspace

Rust library crate for easy implementation of Crate documentation

Rust FUSE - Filesystem in Userspace

A powerful mock object library for Rust

Mock objects are a powerful technique for unit testing software

A powerful mock object library for Rust
Http

394

HTTP mocking for Rust!

Before upgrading, make sure to check out the rustfmt as a general code style

HTTP mocking for Rust!
Http

299

HTTP mocking library for Rust

Advanced verification and debugging support

HTTP mocking library for Rust

Implementation of mock service for testing emails in Rust using

You can find the relevant code in the identically named workspaces above

Implementation of mock service for testing emails in Rust using
Facebook Instagram Twitter GitHub Dribbble
Privacy