Writing Tests with JUnit 5

Trisha Gee

In this tutorial we’re going to look at features of JUnit 5 that can make it easier for us to write effective and readable automated tests. All code in this tutorial can be found in this GitHub repository.

This blog post covers the same material as the video. This provides an easy way for people to skim the content quickly if they prefer reading to watching, and to give the reader/watcher code samples and links to additional information.

Setting up Gradle for JUnit 5

This tutorial uses Gradle, for information on how to add JUnit 5 via Maven take a look at our blog and video on Migrating to JUnit 5 from JUnit 4.

Given a Gradle build file, use ⌘N (macOS) or Alt+Insert (Windows/Linux) to add a new dependency. Typing "junit" in the artifact search box should give a list of possible dependencies.

JUnit 5 dependencies

Use Tab to jump into the dependencies list and use the down arrow until org.junit.jupiter:junit-jupiter is selected. Use the right arrow to open up the version options for this dependency, and choose version 5.6.2 (the most recent production version at the time of writing).

JUnit 5.6.2

NOTE: if you try to search for a dependency and you don’t get the results you expect (either no results, or the versions seem out of date), make sure IntelliJ IDEA has an updated Maven Repository via the settings.

You should see an icon in the top right of the Gradle build file when it has been changed. You must load the Gradle changes if you want IntelliJ IDEA to apply them.

Click on the icon, or use ⇧⌘I, or Ctrl+Shift+O on Windows and Linux, to load the changes. Once the Gradle dependency changes have been loaded, we can see the junit-jupiter dependencies in the External Libraries section of our project window.

There’s one last step we need to do for Gradle in order to correctly use JUnit 5. We need to tell Gradle to use the JUnit Platform when running the tests, by adding useJUnitPlatform() to the test section. The final build.gradle file should look like this:

plugins < id 'java' >repositories < mavenCentral() >dependencies < compile 'org.junit.jupiter:junit-jupiter:5.6.2' >test

Creating and Running a Test

Now the JUnit dependency is set up correctly, we can create our first JUnit 5 test. Create an ExampleTest using the shortcut to generate code (⌘N or Alt+Insert) in the project window.

Create a new test class

Use the same shortcut again inside the class itself to get IntelliJ IDEA to generate a new valid test method for us.

If you’re familiar with JUnit 4, you’ll see the basic test method looks exactly the same, and we can use whichever format name we usually use for our tests. The only difference with JUnit 5 is that it uses the Test annotation from the jupiter package.

import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.Test; public class ExampleTest < @Test void shouldShowSimpleAssertion() < >>

JUnit 5 has an Assertions class for all the common assertions we might want to make. We can use partial completion to find the assertion that we want, for example assertEquals.

Code completion

Now we have our most basic test case:

@Test void shouldShowSimpleAssertion()

Run it to make sure everything works. You can run with:

When the test runs, IntelliJ IDEA shows the result in the run tool window (⌘4 or Alt+4). If the details of the passing tests are hidden, we can show all the tests that passed by clicking on the tick in the top left.

Run window

Double clicking on the test method name takes us back to that method in the code.

One thing to note for JUnit 5 tests is that the test method doesn’t need to be public in order to work. IntelliJ IDEA will let you know if the class or method can have reduced visibility and still work. Use Alt+Enter to have the IDE remove public from the class declaration, and re-run the test to make sure it works as expected.

Change the test so that it should fail:

class ExampleTest < @Test void shouldShowSimpleAssertion() < Assertions.assertEquals(1, 2); >>

When a test fails, IntelliJ IDEA shows the failing test in amber since the test failed an assertion, rather than causing an error (which would be shown in red). We can see the expected value and the actual value side by side, and this should give us an idea of what failed and how.

Failed tests

In our case the cause of the problem should be quite clear since we intentionally put the wrong number in as the "actual" argument.

Configuration: Parameter Hints

Note that IntelliJ IDEA’s parameter hints feature is really helpful for assertion methods. It’s not clear from the method signature which argument is the expected result and which is the actual result. IntelliJ IDEA shows the names of the method parameters as hints, so we can see at a glance which is which.

Parameter name hints

If we decide this is too much noise in the editor, we can turn off hints for a specific method using Alt+Enter on the hint and selecting "Do not show hints for current method". We can also configure the parameter hints from the IDE preferences, in Editor -> Inlay Hints -> Java -> Parameter hints. We can turn hints on or off and configure which types of methods show hints. We can also see the Exclude list, and remove items from the Exclude list if we decide we want to see hints for this method.

Configuration: Test Runner

We can configure how IntelliJ IDEA runs our unit tests if we’re using Gradle. By default IntelliJ IDEA uses Gradle to build and run the code and tests in Gradle projects. This ensures that when we run the application or tests in the IDE, it works the same way as it would in other environments like the command line or a continuous integration environment. It also ensures that any complex build or setup logic, or code generation, is done. However we might choose to use the IntelliJ IDEA runner to run our tests. In some circumstances this might be faster than using Gradle and provide a faster feedback loop.

Disabling or ignoring tests

Quite often we want to say we don’t want a test to be run. This is common with Test Driven Development as tests will, by definition, fail when we first write them. JUnit 5 supports this with a @Disabled annotation. We can add descriptive text to state why the test is not to be run.

@Test @Disabled("Not implemented yet") void shouldShowSimpleAssertion()

NOTE: tests should usually only be disabled for a short period of time, until the code they are testing is working. If a test is disabled for a long time, perhaps because we don’t know why it doesn’t work or what its expected behaviour is, it’s not adding any value to the test suite. A test like this should be removed.

Like passing tests, IntelliJ IDEA usually hides the full list of disabled tests so we can focus on just the failures. Show all disabled tests by clicking on the grey disabled icon. Click on the test name to see the reason the test was disabled.

Running disabled tests

Helpful test names for display

JUnit 5 supports a @DisplayName for the test method, so we can add a helpful descriptive name for the test.

@Test @DisplayName("Should demonstrate a simple assertion") void shouldShowSimpleAssertion()

When we run the test, it’s this DisplayName that shows in the run window:

Test display name

Not only does this encourage us to be descriptive, since it’s a text string and not a method name, it supports special characters, which can help readability.

IDE Tip: Live Templates

If we have a standard template for new test methods that we’d like to follow, we could change the default test method template in IntelliJ IDEA, or we could write a Live Template which helps us to create new test methods that look exactly the way we want.

Let’s create a live template to generate a new test method with a DisplayName that is initially converted into a CamelCase and applied to the method name. This encourages us to use the DisplayName annotation to write readable test descriptions, and uses them to create valid method names so the method name is also helpful. The code our Live Template should generate will look something like this:

@Test @DisplayName("Should check all items in the list") void shouldCheckAllItemsInTheList()

It’s good practice to have generated tests automatically insert a fail into the generated method – any test should fail first even if we haven’t finished writing it yet

To create this live template, open the preferences and go to Editor -> Live Templates.

Live template preferences

Using the "+" in the top right of the scroll pane, create a new live template group called "Test". With this group selected, using the "+" again to create a new live template.

In the live template details in the bottom of the screen:

The key to live templates is creating the template text. This is quite a complex template, so the text is quite advanced:

@org.junit.jupiter.api.Test @org.junit.jupiter.api.DisplayName("$TEST_NAME$") void $METHOD_NAME$()

NOTE: Use fully qualified names (package name plus class name) for the annotations so IntelliJ IDEA knows exactly which class you want. Tick "Shorten FQ names" to have IntelliJ IDEA automatically add the correct import and use only the class name in the annotation.

on my live templates, then, when the code is inserted into the class file it usually follows the same standards as the rest of the application.

Test live template

You need to define the scope the live template applies to, otherwise the IDE won’t know in which sorts of files and at which time it should suggest this template. Click the "define" link next to the "No applicable contexts" warning, and select Java -> Declaration. IntelliJ IDEA will now add this to the list of suggestions when we’re in a Java class file.

Notice the variables in the template. Some of these are built in to the IDE, for example $END is where the caret will end up when the live template finishes inserting all the code. Some are values you’re going to have to define. Let’s define those now. Click on the "Edit variables" button to bring up the variables window.

Live template variables

Set the following values for the variables: