Recently, I was looking for a way to move from JUnit4 to JUnit5, but I found it difficult to search for materials here and there, so I decided to summarize it.
For a small project, I think it's possible to change the notation from JUnit4 to JUnit5 at once, but for a large project, the quantity is strict, so basically I think it's stable to proceed as follows. ..
The second one above works as long as junit-vintage-engine is in the dependent library, but I think it will come when I have to do it, so at any time.
By the way, the official migration method of JUnit is → https://junit.org/junit5/docs/current/user-guide/#migrating-from-junit4
First, switch to the JUnit5 library (the following is Maven, but in the case of Gradle, please change it appropriately [^ gradle]) [^ gradle]: For Gradle settings, refer to the official https://github.com/junit-team/junit5-samples/tree/main/junit5-migration-gradle.
I think it was originally written in JUnit4 as follows.
pom.xml(JUnit4)
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
<scope>test</scope>
</dependency>
Instead of the above content, put the following
pom.xml(JUnit5)
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.vintage</groupId>
<artifactId>junit-vintage-engine</artifactId>
<version>5.7.0</version>
<scope>test</scope>
</dependency>
By the way, I'm using InteliJ, so I added the following
(Just looking at the official message Only needed to run tests in a version of IntelliJ IDEA that bundles older versions
, I wondered if the new InteliJ wouldn't have to be included.
pom.xml(JUnit5)
<!-- Only needed to run tests in a version of IntelliJ IDEA that bundles older versions -->
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.7.0</version>
<scope>test</scope>
</dependency>
By the way, the meaning of each is as follows with reference to Official explanation. It feels like I'll add others when I need it.
Personally, it was quite easy for JUnit4's @Rule
to disappear.
I used to use the one under org.junit
in JUnit4, but in JUnit5 it becomes the one under org.junit.jupiter.api
, so simply rewrite the Package of import.
Target | JUnit4 Package | JUnit5 Package |
---|---|---|
@Test And |
org.junit.* | org.junit.jupiter.api.* |
fail() And |
org.junit.Assert.* | org.junit.jupiter.api.Assertions.* |
The annotation has changed, so replace it
JUnit4 | JUnit5 |
---|---|
@Before |
@BeforeEach |
@After |
@AfterEach |
@BeforeClass |
@BeforeAll |
@AfterClass |
@AfterAll |
@Ignore |
@Disabled |
@Category |
@Tag |
@BeforeClass
or @AfterClass
due to test hierarchy etc., a little more annotation is required, so I will write it separately below)In addition, the ones that can not be rewritten simply are as follows.
--Switching from @ RunWith
to @ ExtendWith
--Switching from @Rule
or @ClassRule
to @ExtendWith
or @RegisterExtension
I think JUnit4 used inner class and @ RunWith (Enclosed.class)
to organize the tests (like below).
How to organize JUnit4 tests
@RunWith(Enclosed.class)
public class SampleJUnit4Test {
public static class TestCategoryA {
@Test
public void testA1() { ... }
}
public static class TestCategoryB {
@Test
public void testB1() { ... }
}
}
JUnit5 allows hierarchies with @ Nested
and non-static classes.
I wondered if the notation became straightforward (impression).
How to organize JUnit 5 tests
public class SampleJUnit5Test {
@Nested
class TestCategoryA {
@Test
public void testA1() { ... }
}
@Nested
class TestCategoryB {
@Test
public void testB1() { ... }
}
}
As a caveat, if you add @Nested
during the migration process from JUnit4 to JUnit5 but keep it as a static class, a compile error will not occur, but the test execution will be ignored. Please be careful. (I haven't checked the details)
I think I wrote the following in the foreground,
- However, if you use @BeforeClass or @AfterClass in the inner class due to test hierarchy etc., you need a little more annotation, so I will write it separately below)
When migrating JUnit5, the inner class will no longer be static by using a test hierarchy using @ Nested
. Therefore, if you do @BeforeClass
or @AfterClass
in the inner class, an error will occur.
In this case, if you add @TestInstance (Lifecycle.PER_CLASS)
to the target class according to the contents of Official description, a test instance will be created for each test class, and in the inner class You will be able to use @BeforeAll
and @AfterAll
.
Use All system in inner class in JUnit5
public class SampleJUnit5Test {
@Nested
@TestInstance(Lifecycle.PER_CLASS)
class TestCategory {
@BeforeAll
static void beforeAll() { ... }
}
}
Since the Assert method of Exception type has changed, I will change it as well.
In JUnit4, I think I used @Test (expected = SampleException.class)
and ExpectedException
.
For JUnit 4
@Test(expected = NullPointerException.class)
public void NullPointerException occurs() {
/*Tests that expect a NullPointerException*/
}
For JUnit 4
@Rule
public ExpectedException expectedException = ExpectedException.none();
@Test
public void SampleException occurs() {
expectedException.expect(SampleException.class);
expectedException.expectMessage("SampleException message");
/*Tests that expect SampleException to occur*/
}
For JUnit5, use assertThrows
.
In the argument of assetThrows
, pass the class of Exception that is expected to occur and the test code (via lambda expression).
For JUnit 5
@Test
public void NullPointerException occurs() {
assertThrows(NullPointerException.class, () -> {
/*Tests that expect a NullPointerException*/
});
}
If you only want to check the occurrence of exceptions, you can use only assertThrows
, but if you want to test the details of the Exception that occurred including the error message, receive the Exception returned by assertThrows
and write various validations.
For JUnit 5
@Test
public void SampleException occurs() {
SampleException exception = assertThrows(SampleException.class, () -> {
/*Tests that expect SampleException to occur*/
});
assertEquals("SampleException message", exception.getMessage());
}
In JUnit4, I think there is a place where the test is written using @Rule
+ TemporaryFolder
for the test around the file. In JUnit5, @Rule
is gone, so this is also a fix.
It's very simple, though, and what was written in JUnit4 as follows
python
@Rule
public TemporaryFolder temporaryFolder = new TemporaryFolder();
private Path root;
@Before
public void setup() {
root = temporaryFolder.getRoot().toPath().toAbsolutePath();
}
Change it to the following (Note that variables with @ TempDir
will cause an error if they are private
)
python
@TempDir
Path root;
I feel that this is a good feeling because the annoying things have disappeared.
@ RunWith (Theories.class)
+ @ DataPoint
+ @ Theory
)@ParameterizedTest
+ @ValueSource
if the repeat target is a primitive type@ParameterizedTest
+ @ MethodSource
Recommended Posts