Struct wiremock::Mock

source ·
pub struct Mock { /* private fields */ }
Expand description

Given a set of matchers, a Mock instructs an instance of MockServer to return a pre-determined response if the matching conditions are satisfied.

Mocks have to be mounted (or registered) with a MockServer to become effective. You can use:

Check the respective documentations for more details (or look at the following examples!).

§Example (using register):

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    let response = ResponseTemplate::new(200);

    let mock = Mock::given(method("GET")).respond_with(response.clone());
    // Registering the mock with the mock server - it's now effective!
    mock_server.register(mock).await;

    // We won't register this mock instead.
    let unregistered_mock = Mock::given(method("POST")).respond_with(response);
     
    // Act
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);

    // This would have matched `unregistered_mock`, but we haven't registered it!
    // Hence it returns a 404, the default response when no mocks matched on the mock server.
    let status = surf::post(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 404);
}

§Example (using mount):

If you prefer a fluent style, you can use the mount method on the Mock itself instead of register.

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .up_to_n_times(1)
        // Mounting the mock on the mock server - it's now effective!
        .mount(&mock_server)
        .await;
     
    // Act
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);
}

§Example (using mount_as_scoped):

Sometimes you will need a Mock to be active within the scope of a function, but not any longer. You can use Mock::mount_as_scoped to precisely control how long a Mock stays active.

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

async fn my_test_helper(mock_server: &MockServer) {
    let mock_guard = Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .expect(1)
        .named("my_test_helper GET /")
        .mount_as_scoped(mock_server)
        .await;

    surf::get(&mock_server.uri())
        .await
        .unwrap();

    // `mock_guard` is dropped, expectations are verified!
}

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;
    my_test_helper(&mock_server).await;

    // Act

    // This would have returned 200 if the `Mock` in
    // `my_test_helper` had not been scoped.
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 404);
}

Implementations§

source§

impl Mock

source

pub fn given<M: 'static + Match>(matcher: M) -> MockBuilder

Start building a Mock specifying the first matcher.

It returns an instance of MockBuilder.

source

pub fn up_to_n_times(self, n: u64) -> Mock

Specify an upper limit to the number of times you would like this Mock to respond to incoming requests that satisfy the conditions imposed by your matchers.

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        // Default behaviour will have this Mock responding to any incoming request
        // that satisfied our matcher (e.g. being a GET request).
        // We can opt out of the default behaviour by setting a cap on the number of
        // matching requests this Mock should respond to.
        //
        // In this case, once one matching request has been received, the mock will stop
        // matching additional requests and you will receive a 404 if no other mock
        // matches on those requests.
        .up_to_n_times(1)
        .mount(&mock_server)
        .await;
     
    // Act

    // The first request matches, as expected.
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);

    // The second request does NOT match given our `up_to_n_times(1)` setting.
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 404);
}
source

pub fn with_priority(self, p: u8) -> Mock

Specify a priority for this Mock. Use this when you mount many Mock in a MockServer and those mocks have interlaced request matching conditions e.g. mock A accepts path /abcd and mock B a path regex [a-z]{4} It is recommended to set the highest priority (1) for mocks with exact conditions (mock A in this case) 1 is the highest priority, 255 the lowest, default to 5 If two mocks have the same priority, priority is defined by insertion order (first one mounted has precedence over the others).

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .and(path("abcd"))
        .respond_with(ResponseTemplate::new(200))
        .with_priority(1) // highest priority
        .mount(&mock_server)
        .await;

    Mock::given(method("GET"))
        .and(path_regex("[a-z]{4}"))
        .respond_with(ResponseTemplate::new(201))
        .with_priority(2)
        .mount(&mock_server)
        .await;

    // Act

    // The request with highest priority, as expected.
    let status = surf::get(&format!("{}/abcd", mock_server.uri()))
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);
}
source

pub fn expect<T: Into<Times>>(self, r: T) -> Self

Set an expectation on the number of times this Mock should match in the current test case. Expectations are verified when the MockServer is shutting down: if the expectation is not satisfied, the MockServer will panic and the error_message is shown.

By default, no expectation is set for Mocks.

§When is this useful?

expect can turn out handy when you’d like to verify that a certain side-effect has (or has not!) taken place.

For example:

  • check that a 3rd party notification API (e.g. email service) is called when an event in your application is supposed to trigger a notification;
  • check that a 3rd party API is NOT called when the response of a call is expected to be retrieved from a cache (.expect(0)).

This technique is also called spying.

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .up_to_n_times(2)
        // We expect the mock to be called at least once.
        // If that does not happen, the `MockServer` will panic on shutdown,
        // causing the whole test to fail.
        .expect(1..)
        // We assign a name to the mock - it will be shown in error messages
        // if our expectation is not verified!
        .named("Root GET")
        .mount(&mock_server)
        .await;
     
    // Act
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);

    // Assert
    // We made at least one matching request, the expectation is satisfied.
    // The `MockServer` will shutdown peacefully, without panicking.
}
source

pub fn named<T: Into<String>>(self, mock_name: T) -> Self

Assign a name to your mock.

The mock name will be used in error messages (e.g. if the mock expectation is not satisfied) and debug logs to help you identify what failed.

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

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;

    // We have two mocks in the same test - how do we find out
    // which one failed when the test panics?
    // Assigning a name to each mock with `named` gives us better error
    // messages and makes it much easier to debug why a test is failing!
    Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .up_to_n_times(2)
        .expect(1..)
        // We assign a name to the mock - it will be shown in error messages
        // if our expectation is not verified!
        .named("Root GET")
        .mount(&mock_server)
        .await;

    Mock::given(method("POST"))
        .respond_with(ResponseTemplate::new(200))
        .up_to_n_times(2)
        .expect(1..)
        // We assign a name to the mock - it will be shown in error messages
        // if our expectation is not verified!
        .named("Root POST")
        .mount(&mock_server)
        .await;
     
    // Act
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 200);

    // Assert
    // We did not make a POST request, therefore the expectation on `Root POST`
    // is not satisfied and the test will panic.
}
source

pub async fn mount(self, server: &MockServer)

Mount a Mock on an instance of MockServer. The Mock will remain active until MockServer is shut down. If you want to control or limit how long your Mock stays active, check out Mock::mount_as_scoped.

Be careful! Mocks are not effective until they are mounted or registered on a MockServer. mount is an asynchronous method, make sure to .await it!

source

pub async fn mount_as_scoped(self, server: &MockServer) -> MockGuard

Mount a Mock as scoped on an instance of MockServer.

When using mount, your Mocks will be active until the MockServer is shut down.
When using mount_as_scoped, your Mocks will be active as long as the returned MockGuard is not dropped. When the returned MockGuard is dropped, MockServer will verify that the expectations set on the scoped Mock were verified - if not, it will panic.

mount_as_scoped is the ideal solution when you need a Mock within a test helper but you do not want it to linger around after the end of the function execution.

§Limitations

When expectations of a scoped Mock are not verified, it will trigger a panic - just like a normal Mock. Due to limitations in Rust’s Drop trait, the panic message will not include the filename and the line location where the corresponding MockGuard was dropped - it will point into wiremock’s source code.

This can be an issue when you are using more than one scoped Mock in a single test - which of them panicked?
To improve your debugging experience it is strongly recommended to use Mock::named to assign a unique identifier to your scoped Mocks, which will in turn be referenced in the panic message if their expectations are not met.

§Example:
  • The behaviour of the scoped mock is invisible outside of my_test_helper.
use wiremock::{MockServer, Mock, ResponseTemplate};
use wiremock::matchers::method;

async fn my_test_helper(mock_server: &MockServer) {
    let mock_guard = Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .expect(1)
        .named("my_test_helper GET /")
        .mount_as_scoped(mock_server)
        .await;

    surf::get(&mock_server.uri())
        .await
        .unwrap();

    // `mock_guard` is dropped, expectations are verified!
}

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;
    my_test_helper(&mock_server).await;

    // Act

    // This would have returned 200 if the `Mock` in
    // `my_test_helper` had not been scoped.
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 404);
}
  • The expectations for the scoped mock are not verified, it panics at the end of my_test_helper.
use wiremock::{MockServer, Mock, ResponseTemplate};
use wiremock::matchers::method;

async fn my_test_helper(mock_server: &MockServer) {
    let mock_guard = Mock::given(method("GET"))
        .respond_with(ResponseTemplate::new(200))
        .expect(1)
        .named("my_test_helper GET /")
        .mount_as_scoped(mock_server)
        .await;
    // `mock_guard` is dropped, expectations are NOT verified!
    // Panic!
}

#[async_std::main]
async fn main() {
    // Arrange
    let mock_server = MockServer::start().await;
    my_test_helper(&mock_server).await;

    // Act
    let status = surf::get(&mock_server.uri())
        .await
        .unwrap()
        .status();
    assert_eq!(status, 404);
}

Auto Trait Implementations§

§

impl Freeze for Mock

§

impl !RefUnwindSafe for Mock

§

impl Send for Mock

§

impl Sync for Mock

§

impl Unpin for Mock

§

impl !UnwindSafe for Mock

Blanket Implementations§

source§

impl<T> Any for T
where T: 'static + ?Sized,

source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
source§

impl<T> Borrow<T> for T
where T: ?Sized,

source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
source§

impl<T> From<T> for T

source§

fn from(t: T) -> T

Returns the argument unchanged.

source§

impl<T> Instrument for T

source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
source§

impl<T, U> Into<U> for T
where U: From<T>,

source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

source§

type Error = Infallible

The type returned in the event of a conversion error.
source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
source§

impl<T> WithSubscriber for T

source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more