How to replace WireMock @Rule annotation in JUnit 5?
Asked Answered
R

5

102

I'm using WireMock in my tests and have such a line of code:

@Rule
public WireMockRule wireMockRule = new WireMockRule(8080);

I want to switch to JUnit 5. So I added the next dependency (using Gradle):

testCompile('org.junit.jupiter:junit-jupiter-engine:5.1.1')

But there are no suggestions when I'm trying to import @Rule annotation.

Do I need to add another module of JUnit dependency? Or are rules not supported in JUnit 5? If not, how can I replace @Rule annotation to make tests work again?

Radial answered 24/6, 2018 at 17:29 Comment(2)
Check this nice article codeaffine.com/2016/04/06/replace-rules-in-junit5Mitman
There is no direct replacement, Junit Jupiter uses @Extension rather than @Rlue; developers need to port their code - WireMock haven't done this yes. You can implement an @Extension yourself.Carbrey
T
57

In a general way, what you did with @Rule and @ClassRule in JUnit 4 should be done with @ExtendWith and Extension that associated provide a very close feature in JUnit 5.
It works as standards JUnit lifecycle hooks but that it is extracted in a Extension class. And similarly to @Rule, as many Extensions as required may be added for a test class.

To handle the issue you have several possible approaches among :

  • keep the JUnit 4 way (JUnit 5 owns the JUnit Vintage part that allows to execute JUnit 3 or 4 tests).
  • rewrite the @Rule as an Extension.
  • do the actual processing done by WireMockRule (start the server, execute your tests and stop the server) in each test of class with @BeforeEach and @AfterEach hook methods.
  • use a third library that implements the equivalent of WireMockRule in the JUnit 5 Extension way such as https://github.com/lanwen/wiremock-junit5

Note that your issue already discussed in the JUnit 5 Issues.

Traverse answered 24/6, 2018 at 18:8 Comment(1)
For a shortcut on making the extension see the answer https://mcmap.net/q/210465/-how-to-replace-wiremock-rule-annotation-in-junit-5Apothecary
G
14

JUnit 4 annotations @Rule and @ClassRule do not exist in JUnit 5. Basically there is a new extension model that can be used to implement extensions with the same functionality. These extensions can be used with the @ExtendWith annotation.

There is a limited migration support for a subset of JUnit 4 rules in the junit-jupiter-migrationsupport module. Unfortunately, it's only limited to subclasses of ExternalResource and Verifier.

Before wiremock has official support for JUnit you have some workarounds:

  1. Run JUnit 4 tests side by side with JUnit 5 tests with the junit-vintage-engine.
  2. Start and stop the server yourself in the test code.
  3. Use a 3rd party extension like wiremock-junit5 or wiremock-extension.
Gondola answered 24/6, 2018 at 19:12 Comment(0)
C
7

There is now official support for JUnit 5 Jupiter from WireMock 2.31.0.

Docs here: http://wiremock.org/docs/junit-jupiter/

Charpentier answered 9/9, 2021 at 11:33 Comment(2)
Great! Though I still wonder if injecting WireMockRuntimeInfo is the only way to get the assigned port (other than specifying a static port manually). My test methods already have long names. With WireMockRuntimeInfo, the signature is a mile longMientao
Oh, I can inject it in @BeforeEach and make port a field...Mientao
M
1

From the JUnit 5 user guide:

@Rule and @ClassRule no longer exist; superseded by @ExtendWith and @RegisterExtension. See also "Limited JUnit 4 Rule Support".

However, as pointed out by Tom, WireMock has full JUnit Jupiter support since version 2.31.0:

// New JUnit 5 extension
@WireMockTest
class DeclarativeWireMockTest {

    @Test
    void test_something_with_wiremock(WireMockRuntimeInfo wmRuntimeInfo) {
        // The static DSL will be automatically configured for you
        stubFor(get("/static-dsl").willReturn(ok()));
      
        // Instance DSL can be obtained from the runtime info parameter
        WireMock wireMock = wmRuntimeInfo.getWireMock();
        wireMock.register(get("/instance-dsl").willReturn(ok()));
       
        // Info such as port numbers is also available
        int port = wmRuntimeInfo.getHttpPort();
        
        // Do some testing...
    }

}

For more information, please refer to the corresponding docs.

Monastic answered 29/8, 2021 at 9:31 Comment(0)
A
0

The https://github.com/webcompere/java-test-gadgets project lets you solve this in a couple of ways.

You can use its support for JUnit 4 rules via the DangerousRuleAdapter - which will attempt to turn any JUnit 4 rule into a Plugin:

@ExtendWith(PluginExtension.class)
public class DangerousRuleAdapterExampleTest {
    @Plugin
    private DangerousRuleAdapter<WireMockRule> adapter = 
        new DangerousRuleAdapter<>(new WireMockRule());

    @Test
    void theTest() {
        // use wiremock rule here
        WireMockRule rule = adapter.get();
    }

The rule adapters cannot work with rules that inspect the test class or the test method, but make a good attempt at running the rule.

There's also support for running a rule around some code:

    TemporaryFolder temporaryFolder = new TemporaryFolder();

    // let's use this temp folder with some test code
    executeWithRule(temporaryFolder, () -> {
        // here, the rule is _active_
        callSomethingThatUses(temporaryFolder.getRoot());
    });

And you can easily create your own new JUnit 5 plugin by using the PluginExtension and TestResource.of

@ExtendWith(PluginExtension.class)
class TestResourceIsActiveDuringTest {
    private WireMockServer server;

    @Plugin
    private TestResource someResource = TestResource.from(() -> server.start(),
                                                          () -> server.stop());

Apothecary answered 5/2, 2021 at 9:25 Comment(2)
DangerousRule...? LOL. Crazy name choice :).Uncounted
@DutA. I wanted a name that gave people a sense of why it might not always work ;)Apothecary

© 2022 - 2024 — McMap. All rights reserved.