How to replace WireMock @Rule annotation in JUnit 5?
JavaJunit5WiremockJunit RuleJava 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 Extension
s 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 anExtension
. - 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:
- Run JUnit 4 tests side by side with JUnit 5 tests with the junit-vintage-engine.
- Start and stop the server yourself in the test code.
- 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.