JUnit, 4, 5, Jupiter, Vintage
Explore how to deal with all versions from JUnit and how to organize your tests in your project to bring more productivity to your team.
Join the DZone community and get the full member experience.
Join For FreeAfter JUnit 5 was released, a lot of developers just added this awesome new library to their projects, because unlike other versions, in this new version, it is not necessary to migrate from JUnit 4 to 5, you just need to include the new library in your project, and with all the engine of JUnit 5 you can do your new tests using JUnit 5, and the older one with JUnit 4 or 3, will keep running without problem.
But what can happen in a big project, a project that was built 10 years ago with two versions of JUnit running in parallel?
New developers have started to work on the project, some of them with JUnit experience, others not. New tests are created using JUnit 5, new tests are created using JUnit 4, and at some point a developer without knowledge, when they will create a new scenario in a JUnit 5 test that has been already created, they just include a JUnit 4 annotation, and the test became a mix, some @Test
of JUnit 4 and some @Test
of JUnit 5, and each day is more difficult to remove the JUnit 4 library.
So, how do you solve this problem? First of all, you need to show to your team, what is from JUnit 5 and what is from JUnit 4, so that new tests be created using JUnit 5 instead of JUnit 4. After that is necessary to follow the Boy Scout rule, whenever they pass a JUnit 4 test they must migrate to JUnit 5.
Let’s see the main changes released in JUnit 5. All starts by the name, in JUnit 5, you don’t see packages called org.junit5, but rather org.junit.jupiter. To sum up, everything you see with “Jupiter”, it means that is from JUnit 5. They chose this name because Jupiter starts with “JU”, and is the fifth planet from the sun.
Another change is about the @Test
, this annotation was moved to a new package: org.junit.jupiter.api and now no one attribute like “expected,” or “timeout” is used anymore, use extension instead. For example, for timeout, now you have one annotation for this: @Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
. Another change is that neither test methods nor classes need to be public.
Now instead of using @Before
and @After
in your test configuration, you have to use @BeforeEach
and @AfterEach
, and you have also @BeforeAll
and @AfterAll
.
To ignore tests, now you have to use @Disable
instead of @Ignore
.
A great news that was released in JUnit 5 was the annotation @ParameterizedTest
, with that is possible to run one test multiple times with different arguments. For example, if you want to test a method that creates some object and you want to validate if the fields are filled correctly, you just do the following:
@ParameterizedTest
@MethodSource("getInvalidSources")
void shouldCheckInvalidFields(String name, String job, String expectedMessage) {
Throwable exception = catchThrowable(() -> new Client(name, job));
assertThat(exception).isInstanceOf(IllegalArgumentException.class)
.hasMessageContaining(expectedMessage);
}
static Stream<Arguments> getInvalidSources() {
return Stream.of(Arguments.arguments("Jean Donato", "", "Job is empty"),
Arguments.arguments("", "Dev", "Name is empty"));
}
There are so many nice features in JUnit 5, I recommend you check it out the JUnit 5 User Guide, to analyze what is useful to your project.
Now that all developers know what was changed in JUnit 5, you can start the process of removing JUnit 4 from your project. So, if you are still using JUnit 4 in 2024, and your project is a big project, you will probably have some dependencies using JUnit 4. I recommend you analyze your libraries to check if some of them are using JUnit 4.
In the image below I’m using Dependency Analyzer from IntelliJ.
As you can see, jersey-test is using JUnit 4, that is, even if I remove JUnit 4 from my project, JUnit 4 will be available to use because Jersey. The easier way will be to bump jersey to 2.35 because JUnit 5 was introduced in jersey-test 2.35, but I can’t update the jersey-test framework because other libraries will break in my project. So, in this case, what can I do?
I can exclude JUnit from Jersey with Dependency Exclusions from Maven (like the image below). That way JUnit 4 will not be used anymore, but rather our JUnit 5.
When you run some tests that use Jersey, they will not be loaded, because there are methods in Jersey using JUnit 4 annotations, setUp
and tearDown
, using @Before
and @After
. To solve this, you can create one “Configuration Class” whose extends JerseyTest
implementing setUp
and tearDown
with @BeforeEach
and @AfterEach
calling super.setUp()
and super.TearDown()
.
public class JerseyConfigToJUnit5 extends JerseyTest {
@BeforeEach
public void setUp() throws Exception {
super.setUp();
}
@AfterEach
public void tearDown() throws Exception {
super.tearDown();
}
}
So, if you have already checked your libraries and no one has more dependency from JUnit 4, you finally can migrate all your tests to JUnit 5, for this process, there is a good tool that saves you from a lot of work, is OpenRewrite, a automated refactoring ecosystem for source code, they will change all your old packages, the older annotations, and everything to the new one.
That’s it folks, now you and your teammates can enjoy JUnit 5 and relax your mind knowing that new tests will be created with JUnit 5 and the project will not become a Frankenstein. So, remember, keep your project up-to-date, because if you forget your libraries, each day will be more difficult to update, always use specifications, and frameworks that follow the specifications, and have a good design in your code, this permits you to change and move with the facility.
Opinions expressed by DZone contributors are their own.
Comments