Wiremock: WireMock with JUnit 5

Created on 9 Jun 2017  路  41Comments  路  Source: tomakehurst/wiremock

In JUnit 5, @Rule and @ClassRule is superseded by @ExtendWith, which requires extension class.
And it seems like extension for WireMock is not yet supported.
Is there any alternative way to use WireMock with stubbing and verification via JUnit 5?

Feature request

Most helpful comment

I'm coming around to the idea of making both JUnit 4 and 5 optional/provided dependencies. I'm going to look at this (with the usual caveats about being busy and it not happening quickly).

All 41 comments

You can programmatically start and stop WireMockServer. That's all the rule is doing really.

I'll mark this as a feature request as JUnit 5 support should start to be a priority soon.

Thank you for your comment, and marking.
Actually, I tried to use WireMock with JUnit, and there was no other way to do it without using JUnit 4.x Rule.
Thanks !

You can use @Before and @After annotated methods to start and stop a WireMockServer in JU4.

Some of WireMock's own acceptance tests actually do this in their base class, so might be worth checking that out if you're not sure what I mean.

Thanks for your kind comment. I'll check it.

Please look at https://github.com/lanwen/wiremock-junit5 (will be available in maven central soon)

@lanwen nice! Could you do this as class level fields instead of (or additionally) method parameters?

@sta-szek Like a class rule?

@lanwen exactly - just to simplify as much as possible.

@lanwen thanks for the nice code!

What the difference?

It's an approach that uses annotated fields. See ExampleTest

@lanwen can you help me how to wiremock-junit5 for custom port.
As in your code, as per my understanding, we can get any random port, but if you want a specific port for wiremock, can you specify how to do that.

void function(@WiremockResolver.Wiremock WireMockServer server) throws IOException {
....
}

but in this, i can't set server port for which server need to start,
I was checking the code of wiremockResolver, this was the code,
this.server = new WireMockServer(((WiremockConfigFactory)mockedServer.factory().newInstance()).create());
i guess, due to this.. i am unable to specify some specific port.

Is there is any way to do that ?
Please unicast me

You can programmatically start and stop WireMockServer. That's all the rule is doing really.

I'll mark this as a feature request as JUnit 5 support should start to be a priority soon.

Any news about this?

@ghilainm for me rewriting rule to Junit5 extension looks like this: https://github.com/jmayday/wiremock/commit/908cbb20d19cf7dcabcca3de28a2712fd895e472 (I'm not sure if it satisfies requirements for pull request though... @tomakehurst?)

As server starts on random port, we need to build also a webclient with correct url. It might be achieved in beforeAll method in a test class:

  @BeforeAll
  static void setup(@ServerUrl String serverUrl) {
    // build webclient using server url
  }

I'm a bit reticent about making WireMock dependent on both JUnit 4 and 5. Dropping 4 isn't an option at the moment as it's still pretty widely used.

Do you think there's much disadvantage in adding JUnit 5 support via a separate library?

Do you think there's much disadvantage in adding JUnit 5 support via a separate library?

Yes, an official but optional library should be quite helpful.

What about splitting Wiremock library in two -- wiremock-core and wiremock-junit4 and adding wiremock-jupiter for JUnit 5 support?

The wiremock library could then simply have a dependency on core and junit4 for the sake of legacy users?

@luolong that doesn't sound much different from what we have now, if you consider @lanwen's library to be the jupiter version.

Having an 'official' Wiremock JUnit5 extension would be valuable. I actually expected to find a JUnit 5 extension when I have a JUnit 4 rule. And I think an optional dependency on JUnit 5 would be no problem at all, would it?

@tomakehurst Sure, I realize that this is not so much different from what you have now. This is by design.

The only difference is that JUnit 4 dependency is explicitly divorced from the core dependency.
The separate modules could even share the same repository and release schedule.

Should not be difficult to achieve.

I'm coming around to the idea of making both JUnit 4 and 5 optional/provided dependencies. I'm going to look at this (with the usual caveats about being busy and it not happening quickly).

Any update on this?

Any update on this?
Currently, I am using @JensPiegsa implementation, but would be great to have an "official" artifact from Wiremock repository.

@tomakehurst Is this something any of us could help with? I can imagine splitting out the junit4 dependencies can be a hairy task with some architectural impact, so I would understand if you want to do it yourself since Wiremock is your baby :-)
But otherwise, let us know!

@fransflippo @tomakehurst I would recommend using:

@AutoConfigureWireMock from our friends from spring's 'org.springframework.cloud:spring-cloud-contract-wiremock' - it's working great with Junit5 and you can customize it it you want :)

@fransflippo @tomakehurst I would recommend using:

@AutoConfigureWireMock from our friends from spring's 'org.springframework.cloud:spring-cloud-contract-wiremock' - it's working great with Junit5 and you can customize it it you want :)

Thanks @blocha , will take a look!

@fransflippo the JUnit 4 dependency is already optional, so it might be quite straightforward to do something similar with JUnit 5.

I'd definitely welcome a PR to add this if you'd like to contribute.

I like the approach @lanwen has taken i.e. creating JUnit 5 extensions to inject WireMock classes as test method parameters, although I'd be inclined to inject an instance of WireMock rather than WireMockServer.

Canned rules are sometimes more trouble than they are worth. My workaround:

private WireMockServer wireMockServer;

@BeforeEach public void proxyToWireMock() {
    wireMockServer = new WireMockServer(WireMockConfiguration.options()/*.port(etc)*/);
    wireMockServer.start();
}

@AfterEach public void noMoreWireMock() {
    wireMockServer.stop();
    wireMockServer = null;
}

There is one aspect the rules were quite good at that are not possible anymore with @lanwen's or @JensPiegsa's implementations: Having more than one mock server. We have one server that talks to several others, and having different mock servers made the tests more readable. Theoretically, we can only use one mock server, but then it is hard to understand where each request is supposed to be sent.

We could also do this like @jglick suggests, but this scales badly, too.

@fdw There is support for multiple server instances. Please have a look at the example.

@fdw this is a very good point, and I think any solution should attempt to cleanly support multiple instances. I haven't looked at JUnit5 extension architecture at all closely, so I'm open to suggestion as to how this could be done.

@JensPiegsa You are right, I hadn't seen that example. Thank you :)

If it helps anyone, we are doing multiple wiremock servers with this single extension class:

class WireMockExtension extends WireMockServer implements BeforeEachCallback, AfterEachCallback {

    @Override
    public void beforeEach(ExtensionContext context) {
        this.start();
    }

    @Override
    public void afterEach(ExtensionContext context) {
        this.stop();
        this.resetAll();
    }
}

Use it with multiple servers in a test like this:

        @RegisterExtension
        WireMockExtension mockServer1 = new WireMockExtension(8081)

        @RegisterExtension
        WireMockExtension mockServer2 = new WireMockExtension(8082)

I'm getting this odd error, if I try to use wiremock with JUnit 5...

@AfterAll
public void after() throws Exception {
    super.tearDown();
    wireMockRule.shutdown();
}

error: cannot access MethodRule
[ERROR] class file for org.junit.rules.MethodRule not found

It only happens if I try to do the shutdown. Is there another way I can shut down the server without triggering this error?

ahh, how silly. I had copied and pasted some snippits from demos, and was trying to do new WireMockRule(8089) instead of new WireMockServer(8089), which obviously hits a class that has dependencies on the Junit 4 API.

@jterhune In my case I also had to add WireMock.configureFor to your solution:

 @Override
    public void beforeEach(ExtensionContext context) {
        this.start();
        WireMock.configureFor("localhost", port());
    }

Otherwise WireMock used port 8080 for admin mappings and can't connect to it the tests.

Hello,

If you're ok with that, I can try to add this feature in WireMock.

Recently, I have setup WireMock in a project at work. I was a little bit surprised that this is not already part of WireMock and we need to add an other library to add this kind of extension.

First at all, I took a look of some repositories such as :

It gave my some inspiration but I found that each extensions had some missing features. For example, none of these 3 JUnit extensions allow you to have an alternative between constructor injection, field injection or method injection.

For the configuration, somes extension didn't seem very clear to me. However, there are great ideas in each of these community extensions.

I can try to put all ideas together and maybe to add new one to have an official JUnit 5 extension for WireMock.

What do you think of that ?

If you're willing to work on this, that would be awesome. JUnit 5 is very high on my priority list, but I've just not had time to devote to it.

Happy to provide support and design input as you need it.

Great to see @Patouche step in to add a JUnit Jupiter extension 馃殌

In the meantime and for those who are looking for a solution to start WireMock before all test methods (as far as I can see it, no community extension allows this as they are implementing the BeforeEachCallback) especially when writing tests that involve a SpringTestContext where one wants to set e.g. the base URL prior to starting the application, I used the following setup over the past months:

public class WireMockInitializer 
  implements ApplicationContextInitializer<ConfigurableApplicationContext> {

  @Override
  public void initialize(ConfigurableApplicationContext configurableApplicationContext) {
    WireMockServer wireMockServer = new WireMockServer(new WireMockConfiguration().dynamicPort());
    wireMockServer.start();

    configurableApplicationContext
      .getBeanFactory()
      .registerSingleton("wireMockServer", wireMockServer);

    configurableApplicationContext.addApplicationListener(applicationEvent -> {
      if (applicationEvent instanceof ContextClosedEvent) {
        wireMockServer.stop();
      }
    });

    TestPropertyValues
      // override any base URL of your HTTP clients here
      .of(Map.of("todo_base_url", "http://localhost:" + wireMockServer.port()))
      .applyTo(configurableApplicationContext);
  }
}

With the initializer above you'll start WireMock as part of the bootstrapping phase of the Spring Context, register it as a Spring Bean and can override base URLs for your HTTP clients.

Next, you need to activate/include this initializer with @ContextConfiguration:

@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
@ContextConfiguration(initializers = {WireMockInitializer.class})
class TodoControllerIT {

  @Autowired
  private WireMockServer wireMockServer;

  @AfterEach
  public void afterEach() {
    this.wireMockServer.resetAll();
  }
}

You can find a detailed explanation as part of this blog post.

Was this page helpful?
0 / 5 - 0 ratings