How to replace WireMock @Rule annotation in JUnit 5?

JavaJunit5WiremockJunit Rule

Java Problem Overview


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?

Java Solutions


Solution 1 - Java

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.

Solution 2 - Java

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.

Solution 3 - Java

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

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

Solution 4 - Java

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());

Solution 5 - Java

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.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionIKoView Question on Stackoverflow
Solution 1 - JavadavidxxxView Answer on Stackoverflow
Solution 2 - JavaArho HuttunenView Answer on Stackoverflow
Solution 3 - JavaTomView Answer on Stackoverflow
Solution 4 - JavaAshley FriezeView Answer on Stackoverflow
Solution 5 - Javabeatngu13View Answer on Stackoverflow