Porting Your Existing Tests to JUnit5

What I wished I knew in advance

Uberto Barbini
Sep 12, 2017 · 5 min read
Image for post
Image for post

On the 10th of September JUnit5 finally reached the General Availability stage.

If you don’t know what I am talking about, you can look at JUnit 5 User Guide or a Gentle introduction to JUnit5.

There are several tutorials on the new cool features of JUnit5, previously known as project Jupiter, but I couldn’t find any experience report on migrating a medium sized test base (a little more than 200 tests) from JUnit4.


it’s pretty painless but require some trivial changes to all your tests.

Slightly longer version

So first step is to update maven o gradle dependencies. Here are my new gradle ones:

testCompile group: ‘org.junit.jupiter’, name: ‘junit-jupiter-api’, version: ‘5.0.0’testRuntime(“org.junit.jupiter:junit-jupiter-engine:5.0.0”)testRuntime(“org.junit.platform:junit-platform-launcher:1.0.0”)

The last one could be not really needed, depending on your IDE version.

Now, there are two possible way of action, either we switch one test at the time or we switch all together and then use some find/replace to fix the compilation errors.

Since I don’t particularly enjoy fixing code for hours I choose the latter. So I removed all the JUnit4 dependencies from Gradle and looked at the many compilation errors.

1) Imports

First I had to fix the imports, so I replaced all

import org.junit.Test;


import org.junit.jupiter.api.*;

and all

import static org.junit.Assert.*;


import static org.junit.jupiter.api.Assertions.*;

With same system I have also removed all the rest of JUnit4 imports, like Ignore, Before etc.

1bis) Little digression about AssertJ

I used this opportunity to also add AssertJ (Fluent assertions for java) you may consider it as well. In case you need to add also:

import static org.assertj.core.api.Assertions.*;

Here are some example of rewritten assertions with AssertJ:


assertTrue( elapsed < 5);assertTrue( mystring.contains("ABC"));


assertThat( elapsed).isLessThan(5);assertThat( mystring).contains("ABC");

2) @Before and @After

The JUnit4 Before assertion is split in JUnit5 in BeforeAll and BeforeEach. Those are exactly like Before and BeforeClass annotation of JUnit4.

BeforeAll is run only once for class, BeforeEach is run before each test. What’s more, the BeforeAll must be a static method.

What I did is to replace all @Before with @BeforeEach and then created a method annotated with @BeforeAll where really needed (just a few places).

I didn’t used After annotation but in case it would be same thing, with @AfterAll and @AfterEach.

Maybe I’m just nostalgic but I liked better when there was only the setUp and tearDown methods without need of any annotation. Is there really people out there that are so keen to use different method names?

3) Asserts

If you imported statically the Assert class in JUnit4 your asserts should work directly in JUnit5, apart for a problem with messages. If you had Assert.assertxxx calls, you can just remove the “Assert.” part.

All the asserts of JUnit4 are also present in JUnit5, at least as far as I can tell.

Instead there is a problem with messages in asserts: in JUnit4 each assert can have an assertion message that the TestRunner would use if the assertion fail. It is the same in JUnit5 but whilst in JUnit4 and previous this was the first parameters in JUnit5 it is consistently the last one.

I suppose the change is because auto-completion on IDE was easily tricked by having a string at first place if you were comparing strings. Or maybe not, but whatever the reason now you have to switch the parameters to move to JUnit5.


assertNotNull(“User is not present”, user );


assertNotNull(user, “User is not present”);

It’s a bit annoying but the cool thing I have learned is that if you have a recent version of IntelliJ you can use the cool key combination Ctrl+Alt+Shift <arrow left or arrow right> to switch quickly parameters inside functions.

n4) Expected Exceptions

One of the things I didn’t like in JUnit was the suggested way to test for expected Exceptions. I found this annotation ugly and not very precise.

For example I cannot test the exact line where I expect the Exception to be thrown and its message.


In my test base this was not used, and instead I used a try…catch when I needed to test exceptions.

With JUnit5 the situation is much improved with the new assertThrows.

Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");

5) @Ignore

This is very easy: replace all your @Ignore annotations with @Disabled

To be honest I don’t really understand what could be the reason here, it seems a bit gratuitous to me.

6) @RunWith

JUnit had a quite limited way to run tests in special context, like with Mockito or Spring. You need to use the annotation RunWith but you cannot have more than one for class, so it was complicated to use your favourite mocking framework and Spring at the same time.

With JUnit5 you have to use the ExtendWith annotation and you can add several of them to the same class.

Since there is a module using SpringBoot in my project (unfortunately), I had to replace:





After all these changes, at first compile everything went well and I haven’t find any other problem.

All in all it took me about one hour to do the migration.

Now the final question is: “why bother?”. Why not to continue with JUnit4?

Well there are a lot of nice features in JUnit5, like better modularity, better categories, better concurrent testing, etc. but the real killer feature for me is the assertAll.

() -> assertEquals("John", person.getFirstName()),
() -> assertEquals("Doe", person.getLastName())

Or even checking that a map contains all the keys we need, each with a valid value in one go:

assertAll(“keys”, keys.stream().map(k -> (Executable) () -> {   assertNotNull(myMap.get(k), “Null for key “ + k);   assertFalse(myMap.get(k).isEmpty());}));

Previously, the first failed assertion would prevent the others to run, instead now is possible to group some assertions and let them run all and having a full report of which failed and which passed.

I already started to improve my tests with assertJ and assertAll, without doing a big refactoring, now everytime I have to touch a test I will improve it with the new features.

I wish you lot of fun with JUnit5!

Welcome to a place where words matter. On Medium, smart voices and original ideas take center stage - with no ads in sight. Watch
Follow all the topics you care about, and we’ll deliver the best stories for you to your homepage and inbox. Explore
Get unlimited access to the best stories on Medium — and support writers while you’re at it. Just $5/month. Upgrade

Get the Medium app

A button that says 'Download on the App Store', and if clicked it will lead you to the iOS App store
A button that says 'Get it on, Google Play', and if clicked it will lead you to the Google Play store