96

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?

beatngu13
  • 7,201
  • 6
  • 37
  • 66
IKo
  • 4,998
  • 8
  • 34
  • 54
  • Check this nice article https://www.codeaffine.com/2016/04/06/replace-rules-in-junit5/ – Ivan Gammel Jun 24 '18 at 17:34
  • There is no direct replacement, Junit Jupiter uses `@Extension` rather than `@Rlue`; developers need to port their code - WireMock haven't [done this yes](https://github.com/tomakehurst/wiremock/issues/684). You can implement an `@Extension` yourself. – Boris the Spider Jun 24 '18 at 17:48

5 Answers5

56

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.

jzheaux
  • 7,042
  • 3
  • 22
  • 36
davidxxx
  • 125,838
  • 23
  • 214
  • 215
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.
Arho Huttunen
  • 1,081
  • 9
  • 16
6

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

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

Tom
  • 3,471
  • 21
  • 14
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());

Ashley Frieze
  • 4,993
  • 2
  • 29
  • 23
0

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.

beatngu13
  • 7,201
  • 6
  • 37
  • 66