This is my first Qiita.
Taste of JUnit 5 at KANJAVA PARTY 2017 !!! held on June 24, 2017 / junit5falsewei-jian) was announced under the title. The version at the time of announcement was M4, but there are some changes in M5, so I will follow you.
However, since we mainly describe JUnit Jupiter here, please refer to the original JUnit 5 User Guide for other information. Please refer to it.
It is compatible with Jigsaw. Jigsaw isn't very familiar with it, so I'll avoid it.
@ParameterizedTest
parameter now only applies to test methodsIt's a little confusing. Write the code.
In JUnit5M4, since there is an argument at the method callback of setup1, I try to apply the parameter of @ParameterrizedTest
, but it fails because the types do not match. Instead, I was able to receive the parameters of ParameterizedTest in the lifecycle callback method like setup2.
In JUnit5M5, the parameter of @ParameterizedTest
is not applied to the life cycle callback method, so on the contrary, an error will occur at the time of callback of setup2.
This fix is to prevent strange problems when @ParameterizedTest
and normal @Test
are mixed in one test class.
ParameterizedNGTest.java
public class ParameterizedNGTest {
@BeforeEach
void setUp1(TestInfo info) {
}
@BeforeEach
void setUp2(String p1, String p2) {
System.out.println(p1 + p2);
}
@ParameterizedTest
@CsvSource({ "x, 1", "y, 2","z, 3" })
void testIt(String input, String expected) {
}
}
Please be careful when acquiring with Maven or Gradle.
Class names are omitted for items whose class does not change.
Old API | New API | Remarks |
---|---|---|
ParameterResolver#supports() | supportsParameter() | |
ParameterResolver#resolve() | resolveParameter() | |
ContainerExecutionCondition#evaluate() | ExecutionCondition#evaluateExecutionCondition() | ContainerExecutionCondition is abolished |
TestExecutionCondition#evaluate() | ExecutionCondition#evaluateExecutionCondition() | TestExecutionCondition is abolished |
TestExtensionContext#getTestException() | ExtensionContext#getExecutionException() | TestExtensionContext is abolished |
TestExtensionContext#getTestInstance() | ExtensionContext#getTestInstance() | TestExtensionContext is abolished. The return value is also Object-> Optional<Object>Change to |
TestTemplateInvocationContextProvider#supports() | supportsTestTemplate() | |
TestTemplateInvocationContextProvider#resolve() | provideTestTemplateInvocationContexts() | |
ArgumentsProvider#arguments() | provideArguments() | |
ObjectArrayArguments#create() | Arguments#of() | ObjectArrayArguments obsolete |
@MethodSource#names |
value |
@TestInstance
The @TestInstance
annotation is an annotation for controlling the life cycle of a test class.
Until now, JUnit has materialized a test class each time a test method is executed.
TestInstancePerMethodTest.java
@RunWith(JUnitPlatform.class)
public class TestInstancePerMethodTest {
private int i = 0;
@Test
void test1(){System.out.println(i++);}
@Test
void test2(){System.out.println(i++);}
}
Execution result.
0
0
If you give @TestInstance
(and specify Lifecycle.PER_CLASS), the test class will be materialized only once and the result will be different.
TestInstancePerClassTest.java
@RunWith(JUnitPlatform.class)
@TestInstance(Lifecycle.PER_CLASS)
public class TestInstancePerClassTest {
private int i = 0;
@Test
void test1(){System.out.println(i++);}
@Test
void test2(){System.out.println(i++);}
}
Execution result.
0
1
By giving @TestInstance
, the execution cost of the test class will be reduced, but it should be noted that the initialization process must be performed by @BeforeEach
, not at the time of initialization.
At the same time, it should be noted that the story is a little complicated because @BeforeAll
and @AfterAll
must be specified in a way that matches the materialization of the test class.
In other words, if you specify PER_CLASS, you will get a run-time error unless you annotate @BeforeAll
or @AfterAll
to the dynamic method instead of the static method.
Also, if you use @TestInstance
and @Nested
together, you can write @BeforeAll
and @AfterAll
even for nested test classes, so it may be better to use them properly. It may be.
By the way, if you use @TestInstance
, the order of life cycle callbacks will change.
CallBackOrderTest.java The output result when is executed as it is is as shown in ①, but when @TestInstance
is annotated, it is as shown in ②.
I think it's a hassle, but if you think about it normally, that's the result.
①.
ExecutionCondition:false
beforeAll
postProcessTestInstance
ExecutionCondition:true
beforeEach
beforeTestExecution
foo
handleTestExecutionException
afterTestExecution
afterEach
afterAll
②.
postProcessTestInstance
ExecutionCondition:false
beforeAll
ExecutionCondition:true
beforeEach
beforeTestExecution
foo
handleTestExecutionException
afterTestExecution
afterEach
afterAll
Until JUnit5M4, when an exception occurred in each Executable without assertAll, the subsequent Executable was treated as an error without evaluation, but after M5, an exception other than the blacklist exception occurred. But the evaluation is no longer interrupted. The execution result of M4 and M5 when there is the following code is shown below.
AssertAllInExceptionTest.java
@RunWith(JUnitPlatform.class)
public class AssertAllInExceptionTest {
@Test
void thrownNullPointerException() {
assertAll(
() -> {throw new NullPointerException();},
() -> assertEquals(2, 3)
);
}
}
M4 execution result | Execution result of M5 |
---|---|
You can see that M4 is evaluated as Error, M5 is evaluated as Failure, and the second Executable is evaluated.
Later, I used the word "blacklist exception" earlier, but there is a question that "that's what it is!". In the User Guide, the word "blacklisted exception" was mentioned in the part of the announcement of the specification change of assertAll and the release note of M2 in the other part.
If the exception is a blacklisted exception such as an OutOfMemoryError, however, it will be rethrown.
The answer to the question "What is such as (etc.) !! What else is there !!" was not in the User Guide but in the code.
[BlacklistedExceptions.java](https://github.com/junit-team/junit5/blob/r5.0.0-M4/junit-platform-commons/src/main/java/org/junit/platform/commons/util/ Looking at the code called BlacklistedExceptions.java), it seems that it is currently only OutOfMemoryError.
@TestTemplate
has been documentedIt seems that it was from JUnit5M4, but I overlooked it because it was not written in the User Guide. There was a description in the User Guide of JUnit5M5, so I will write an overview here.
I think @TestTemplate
, like @ParameterizedTest
, is for separating test code and test data.
I found out by reading the code, but since @ParameterizedTest
is an annotation that annotates @TestTemplate
, I think that @TestTemplate
should not be a concern if you are not dissatisfied with @ParameterizedTest
. I will.
The following is a slightly modified version of the User Guide machine translation.
3.14. Test Templates
The @TestTemplate
method is a template for test cases, not regular test cases.
Therefore, it is designed to be called multiple times, depending on the number of call contexts returned by the registered provider.
Therefore, @TestTemplate
should be used in conjunction with an Extension that implements TestTemplateInvocationContextProvider.
Invoking a test template method behaves like running a normal @ Test
method and fully supports the same lifecycle callbacks and extensions.
For usage examples, see Providing Invocation Contexts for Test Templates.
5.8. Providing Invocation Contexts for Test Templates
The @TestTemplate
method can only be executed if at least one TestTemplateInvocationContextProvider is registered.
Each of these providers provides a stream of TestTemplateInvocationContext instances.
Each context can specify a custom display name and a list of additional extensions to use only in the next call to the @TestTemplate
method.
The following example describes a test template and shows how to register and implement a TestTemplateInvocationContextProvider.
@TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String parameter) {
assertEquals(3, parameter.length());
}
static class MyTestTemplateInvocationContextProvider implements TestTemplateInvocationContextProvider {
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(ExtensionContext context) {
return Stream.of(invocationContext("foo"), invocationContext("bar"));
}
private TestTemplateInvocationContext invocationContext(String parameter) {
return new TestTemplateInvocationContext() {
@Override
public String getDisplayName(int invocationIndex) {
return parameter;
}
@Override
public List<Extension> getAdditionalExtensions() {
return Collections.singletonList(new ParameterResolver() {
@Override
public boolean supportsParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return parameterContext.getParameter().getType().equals(String.class);
}
@Override
public Object resolveParameter(ParameterContext parameterContext,
ExtensionContext extensionContext) {
return parameter;
}
});
}
};
}
}
In this example, the test template is called twice. The display name of the call will be the "foo" and "bar" specified in the call context. Each call registers a custom ParameterResolver that will be used to resolve the method parameters. The output when using ConsoleLauncher is:
└─ testTemplate(String) ✔
├─ foo ✔
└─ bar ✔
The TestTemplateInvocationContextProvider extension API primarily allows you to prepare test class instances separately with different contexts—for example, with different parameters, or create multiple times without changing the context. Tests in — Mainly used to implement various tests that rely on repeated calls to similar methods.
@ParameterizedTest
accepts an array as an argumentProbably in response to this Issue, if you try to simply output an array object in Java [Ljava.lang.String; @ 7c29daf3
I think I fixed the fact that I couldn't see the contents.
However, I couldn't verify it because I couldn't write a little code that can be compared between M4 and M5. Excuse me.
@EnumSource
has changedIn M4, the names of @ EnumSource
specified the Enum name to be acquired, but with the addition of the property called mode in M5, the meaning of the information passed to names can be changed. It was.
Mode | Meaning of names |
---|---|
INCLUDE | Default value. Applies only to Enum names specified in names |
EXCLUDE | Applies only to Enum names not specified in names |
MATCH_ALL | Applies only Enum names that match all the regular expressions specified in names |
MATCH_ANY | Applies only Enum names that match any of the regular expressions specified in names |
(Soliloquy) Do you want to use it that much?
@MethodSource
has changedIt is no longer an error to specify DoubleStream, IntStream, LongStream as the return value of the method specified by @MethodSource
.
@TestFactory
has changed@TestFactory
now supports any nested dynamic container. For more information, see DynamicContainer and the abstract-based DynamicNode. See junit5 / docs / current / api / org / junit / jupiter / api / DynamicNode.html).
It is that. A sample is also attached to the User Guide.
@TestFactory
Stream<DynamicNode> dynamicTestsWithContainers() {
return Stream.of("A", "B", "C")
.map(input -> dynamicContainer("Container " + input, Stream.of(
dynamicTest("not null", () -> assertNotNull(input)),
dynamicContainer("properties", Stream.of(
dynamicTest("length > 0", () -> assertTrue(input.length() > 0)),
dynamicTest("not empty", () -> assertFalse(input.isEmpty()))
))
)));
}
Looking at this, I somehow became able to see how to utilize Dynamic Test. Is DynamicTest a mechanism that makes it easy to translate tests written by an external DSL into a structured set of test code so that it can be reported properly?
@BeforeAll
.Strictly speaking, it seems to be an exception that occurred in the method that annotated @BeforeAll
or the BeforeAllCallback interface implementation method.
I wasn't aware of it, but it means that I couldn't do it with M4. I looked it up, but in M4 the argument of AfterAllCallback # afterAll was ContainerExtensionContext, and there was no API to get the exception that occurred. From M5, the Container Extension Context has been integrated into the Extension Contedxt so it can be captured.
In the same theory, exceptions thrown by @BeforeEach
can be caught by the AfterEachCallback implementation interface. (Available at M4)
Yeah, I'm not sure.
Extensions may now share state across top-level test classes by using the Store of the newly introduced engine-level ExtensionContext.
However, there are too few explanations about the Store ...
Only the ones that are different / new from the time of the M4 document, but they are as follows.
Old maturity | New maturity | |
---|---|---|
@TestInstance |
- | Undescribed |
@TestTemplate |
- | Experimental |
Assertions#assertAll | Maintained | Experimental |
Assumptions#assumingThat | Maintained | Experimental |
DynamicContainer | - | Experimental |
DynamicNode | - | Experimental |
ExecutionCondition | - | Experimental |
TestTemplateInvocationContextProvider | - | Experimental |
TestTemplateInvocationContext | - | Experimental |
Basically, there are only omissions or additions, and it may not change for each milestone.
Looking at the release notes of the User Guide, the main changes other than Chapter 7 are as follows.
I haven't had many opportunities to announce recently, so I'll do my best for JUnit 5. We hope to keep you informed of the changes, at least until the official release.
The next milestone is M6, but as of July 14, 2017, it is scheduled to be released on July 16, 2017, and the progress seems to be 42%, so it will probably be delayed w
Recommended Posts