In this tutorial, we are going to get to know about parameter resolution in JUnit 5, and we also get through some related examples as well.
1. Parameter Resolution in JUnit 5
In JUnit testing, we can see that almost of the normal test constructors, test methods don’t have any parameters. However, there are some situations that we need to define parameters for those. In such cases, we can use the ParameterResolver class of JUnit 5 which defines the API for Extensions that wish to dynamically resolve parameters at runtime.
So, if a test constructor or a @Test, @BeforeEach, @AfterEach, @BeforeAll, or @AfterAll method accepts a parameter, then the parameter must be resolved at runtime by a ParameterResolver. And parameters may be resolved by name, type, annotation, or any combination thereof.
2. JUnit 5 Parameter Resolution Example
2.1. Preparation
2.1.1. Setup environment
We will need to get JUnit 5 setup in our IDE in order to run all examples in this tutorial. You can refer the following to get JUnit 5 ready with IDE (Eclipse, Intellij) and build tools( Maven, and Gradle).
2.1.2. Download example code
The sample code presented in this tutorial can be found on the Github or you can download here
2.2. Parameter Resolution by type
2.2.1. Problem
As mentioned earlier, in JUnit 5, a parameter can be resolved by type. In this example, we will get through an example that parameter resolution is done by type.
Let’s see a test method which has an auditService parameter as follows:
1 2 3 4 5 6 7 8 9 10 |
@RunWith(JUnitPlatform.class) public class TestOrderService { @Test public void placeOrderOK(AuditService auditService) { assertEquals(1, 1); auditService.audit(); } } |
If we run this method, it will fail and throw an exception:
1 2 3 4 |
org.junit.jupiter.api.extension.ParameterResolutionException: No ParameterResolver registered for parameter [xyz.howtoprogram.junit5.order.AuditService arg0] in executable [public void xyz.howtoprogram.junit5.order.TestOrderService.placeOrderOK (xyz.howtoprogram.junit5.order.AuditService)]. |
The error shows that the auditService parameter need to be resolved at runtime and JUnit 5 was failed to do that. And to make this test passed, we must implement a parameter resolution for it.
2.2.2. Implement the AuditParameterResolver
Let’s see an example AuditServiceParameterResolver class we’re going as below:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class AuditServiceParameterResolver implements ParameterResolver { @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { return new AuditService(); } @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { return (parameterContext.getParameter().getType() == AuditService.class); } } |
The class has to implement the ParameterResolver class. In the supportsParameter method, we check whether the parameter type is AuditService or not. And in the resolveParameter method, we simply return the new instance of the AuditService class.
2.2.3. Register the Parameter Resolution as extension
After defining the AuditServiceParameterResolver class, we need to register it as a JUnit 5 extension. Hence, let’s see the test class that we have just modified as below:
1 2 3 4 5 6 7 8 9 10 11 |
@RunWith(JUnitPlatform.class) @ExtendWith(AuditServiceParameterResolver.class) public class TestOrderService { @Test public void placeOrderOK(AuditService auditService) { assertEquals(1, 1); auditService.audit(); } } |
We have just added one more line:
1 |
@ExtendWith(AuditServiceParameterResolver.class) |
This a way we register an extension in JUnit 5.
2.2.4. Verify the test
The test run gives us the output:
2.3. Parameter Resolution by annotation
2.3.1. Problem
As mentioned above, JUnit 5 allows us to resolve parameters by name, type, annotation, or any combination thereof. In this section, we will get through an example which parameter resolution is done by annotation.
Let’s see the @Report annotation we want to define the below test method:
1 2 3 4 5 |
@Test public void placeOrderNG(@Report ReportService reportService) { reportService.report(); assertEquals(1, 1); } |
2.3.2. Defined the @Report annotation
We are going to define the @Report annotation as below:
1 2 3 4 |
@Target(ElementType.PARAMETER) @Retention(RetentionPolicy.RUNTIME) public @interface Report { } |
2.3.3. Implement the ReportAnnotationParameterResolver
To be able to resolve the @Reportt annotation, we have to implement a ReportAnnotationParameterResolver class as the following:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class ReportAnnotationParameterResolver implements ParameterResolver { @Override public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { return ReflectionUtils.newInstance(parameterContext.getParameter().getType()); } @Override public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException { return parameterContext.getParameter().isAnnotationPresent(Report.class); } } |
In similar to the first example, we have to implement the ParameterResolver class, override two methods: supports and resolve. In the supports method, we check whether the parameter is annotated with the @Report annotation or not. Then in the resolve method, we create and return a new instance of the ReportService class.
2.3.4. Register the Parameter Resolution as extension
We need to register the AuditAnnotationParameterResolver class as an extension of JUnit 5. Therefore, we are going to modify the test class as below:
1 2 3 4 5 6 7 8 9 10 11 |
@RunWith(JUnitPlatform.class) @ExtendWith(ReportAnnotationParameterResolver.class) public class TestOrderService { @Test public void placeOrderOK(@Report ReportService reportService) { reportService.report(); assertEquals(1, 1); } } |
2.3.4. Verify the test
Running the test gives us the Green status.
2.4. Some default parameter resolutions
JUnit 5 comes with some built-in parameter resolutions such as TestInfo and TestReporter. So, in general, we can inject TestInfo and TestReporter into our test methods so that we can obtain any info that we want. The TestInfo JUnit 5 parameter resolution can give us some information about the test such as Display Name, Tags, etc while the TestReporter defines some methods for using with the test result.
Let’s see an example of using built-in TestInfo and TestReporter parameter resolutions of JUnit 5:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 |
@RunWith(JUnitPlatform.class) public class TestOrderService { @DisplayName("Test placeOrder method") @Test public void placeOrderOK(TestInfo testInfo, TestReporter testReporter) { assertEquals("Test placeOrder method", testInfo.getDisplayName()); testReporter.publishEntry("key", "value"); assertEquals(1, 1); } } |
Note that we don’t need to specify any extensions for this test class.
3. Summary
We have learned about parameter resolution in JUnit 5. We also got through some related examples about JUnit 5 parameter resolution. The parameter resolution opens a way for users to inject other objects into test methods in different ways. And currently, JUnit 5 provides us several built-in parameter revolvers such as TestInfo and TestReport which we can leverage to get information about the tests and make test report as well.
4. References
JUnit 5 Basic Introduction – Getting Started With The Next Generation of JUnit
JUnit 5 Disable or Ignore A Test
JUnit 5 Dynamic Tests – Generate Tests at Run-time
JUnit 5 Test Suite – Aggregating Tests In Suites
JUnit 5 Assumptions With Assume
Hello how are you?
Has an erro on your example ReportAnnotationParameterResolver
the name methods change on JUnit5 new version an was add a throws exception:
public boolean supportsParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
public Object resolveParameter(ParameterContext parameterContext, ExtensionContext extensionContext) throws ParameterResolutionException {
Best regards!