wiremock-rs icon indicating copy to clipboard operation
wiremock-rs copied to clipboard

Unable to override mock behaviour

Open mawkler opened this issue 1 year ago • 2 comments

I'm trying to mock an overcomplicated API that I don't own, but that my code makes calls to. For each of my tests I have to mock quite a lot of endpoints, but most of them should behave the same way for all tests. I would therefore like to create a "base mock" that mocks all those endpoints, and then I want to override the base behaviour of one of those endpoints depending on the test.

However, it seems like I can't override the response for a given path if I've already defined it. Here's some code to illustrate the behaviour that I expect:

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

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

    // Define base behavior
    Mock::given(method("GET"))
        .and(path("/api/base"))
        .respond_with(ResponseTemplate::new(200).set_body_string("Base response"))
        .mount(&mock_server)
        .await;

    // Test 1: Use the base behavior
    let response = reqwest::get(&format!("{}/api/base", &mock_server.uri()))
        .await
        .unwrap();
    assert_eq!(response.text().await.unwrap(), "Base response");

    // Test 2: Override the base behavior
    Mock::given(method("GET"))
        .and(path("/api/base"))
        .respond_with(ResponseTemplate::new(200).set_body_string("Overridden response"))
        .mount(&mock_server)
        .await;

    let response = reqwest::get(&format!("{}/api/base", &mock_server.uri()))
        .await
        .unwrap();

    // This assert fails because we get back "Base response"
    assert_eq!(response.text().await.unwrap(), "Overridden response");
}

Is this expected behaviour? If yes, is there some other way to override the base behaviour?

mawkler avatar Oct 26 '24 21:10 mawkler

Yes, this isn't currently supported with an "override" semantic. You can limit how many times the base mock matches, but not much more than that.

LukeMathWalker avatar Oct 27 '24 10:10 LukeMathWalker

I see, thanks for clarifying.

On a side note, thank you very much for writing Zero To Production In Rust! It's an excellent book!

mawkler avatar Oct 28 '24 09:10 mawkler

This might have been implemented after this issue was opened, but I'm pretty sure this can be achieved with priorities.

Give the base mock a low priority and later mocks will be matched before it.

Raniz85 avatar Oct 21 '25 12:10 Raniz85

Thank you for the suggestion! I was able to get the desired behaviour using .with_priority():

Click to expand
use reqwest;
use wiremock::matchers::{method, path};
use wiremock::{Mock, MockServer, ResponseTemplate};

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

    // Define base behavior
    Mock::given(method("GET"))
        .and(path("/api/base"))
        .respond_with(ResponseTemplate::new(200).set_body_string("Base response"))
        .with_priority(6) // <-- I ADDED THIS LINE
        .mount(&mock_server)
        .await;

    // Test 1: Use the base behavior
    let response = reqwest::get(&format!("{}/api/base", &mock_server.uri()))
        .await
        .unwrap();
    assert_eq!(response.text().await.unwrap(), "Base response");

    // Test 2: Override the base behavior
    Mock::given(method("GET"))
        .and(path("/api/base"))
        .respond_with(ResponseTemplate::new(200).set_body_string("Overridden response"))
        .mount(&mock_server)
        .await;

    let response = reqwest::get(&format!("{}/api/base", &mock_server.uri()))
        .await
        .unwrap();

    // This assert fails because we get back "Base response"
    assert_eq!(response.text().await.unwrap(), "Overridden response");
}

See the line with the comment I ADDED THIS LINE.

The priority is 5 by default.

mawkler avatar Oct 28 '25 08:10 mawkler