Introduction to JUnit 5 Test Classes

If you want to learn how you can work smarter and save time when you are writing tests with JUnit 5, you should take a look at my Introduction to JUnit 5 course. It has 24 lessons, 47 exercises, and 13 quizzes.

This blog post describes how we can write our first test class with JUnit 5. After we have finished this blog post, we:

  • Can create test classes with JUnit 5.
  • Know how we can use setup and teardown methods.
  • Understand how we can write simple test methods with JUnit 5.

Let's start by creating our first test class.

Creating Our First Test Class

A test class is a normal Java class that is either public or package private. We can create our first test class by following these steps:

  1. Create a new package private class.
  2. Configure the display name of our test class by annotating it with the @DisplayName annotation. This is an optional step, but I think that we should always use the @DisplayName annotation because it allows us to specify a custom display name that's used by our IDE and other build tools when they create or show test reports. In other words, we can replace a technical name with a sentence that describes the purpose of our test class.

After we have created our first test class, its source code looks as follows:

import org.junit.jupiter.api.DisplayName;

@DisplayName("JUnit 5 Example")
class JUnit5ExampleTest {
    
}
We can add the @DisplayName annotation to a test class or to a test method.

Additional Reading:

We have now created our first test class. Next, we will find out how we can use setup and teardown methods.

Using Setup and Teardown Methods

A test class can have four setup and teardown methods that must fulfill these two conditions:

  • These methods must not return anything. In other words, their return type must be void.
  • Setup and teardown methods cannot be private.

The supported setup and teardown methods are described in the following:

  • The method that's annotated with the @BeforeAll annotation must be static, and it's run once before the test methods are run.
  • The method that's annotated with the @BeforeEach annotation is invoked before each test method.
  • The method that's annotated with the @AfterEach annotation is invoked after each test method.
  • The method that's annotated with the @AfterAll annotation must be static, and it's run once after all test methods have been run.

Let's add these methods to our test class. After we have added these setup and teardown methods to our test class, its source looks as follows:

import org.junit.jupiter.api.*;

@DisplayName("JUnit 5 Example")
class JUnit5ExampleTest {

    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all test methods");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("Before each test method");
    }

    @AfterEach
    void afterEach() {
        System.out.println("After each test method");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("After all test methods");
    }
}

There are three things I want to point out:

  • We write information to System.out only because it's the easiest way to demonstrate the invocation order of setup, teardown, and test methods.
  • All setup and teardown methods are inherited as long as they are not overridden. Also, the setup and teardown methods found from the superclasses are invoked before the setup and teardown methods which are found from the subclasses.
  • The methods which are annotated with the @BeforeAll and @AfterAll annotations must be static only if you create a new test instance for each test method (this is the default behavior of JUnit 5). However, it's also possible to use a setting that creates a new test instance for each test class. If you use the latter option, the methods annotated with the @BeforeAll and @AfterAll annotations don't have to be static.

Additional Reading:

After we have added setup and teardown methods to our test class, we can finally write our first test methods. Let's find out how we can do it.

Writing Our First Test Methods

A test method is a method that fulfills these three requirements:

  • A test method isn't private or static
  • A test method must not return anything. In other words, its return type must be void.
  • A test method must be annotated with the @Test annotation.
If we want to override the display name of a test method, we have to annotate the test method with the @DisplayName annotation.

Let's add two test methods to our test class:

  1. The firstTest() method has a custom display name and it writes a unique string to System.out.
  2. The secondTest() method has a custom display name and it writes a unique string to System.out.

After we have written these two test methods, the source code of our test class looks as follows:

import org.junit.jupiter.api.*;

@DisplayName("JUnit 5 Example")
class JUnit5ExampleTest {

    @BeforeAll
    static void beforeAll() {
        System.out.println("Before all test methods");
    }

    @BeforeEach
    void beforeEach() {
        System.out.println("Before each test method");
    }

    @AfterEach
    void afterEach() {
        System.out.println("After each test method");
    }

    @AfterAll
    static void afterAll() {
        System.out.println("After all test methods");
    }

    @Test
    @DisplayName("First test")
    void firstTest() {
        System.out.println("First test method");
    }

    @Test
    @DisplayName("Second test")
    void secondTest() {
        System.out.println("Second test method");
    }
}
Again, I think that we should specify custom display names to our test methods because we can use real sentences instead of technical names.

Additional Reading:

We have just written our first test methods. Let's see what happens when we run our unit tests.

Running Our Unit Tests

When we run our unit tests, we should see the following output:

Before all test methods
Before each test method
First test method
After each test method
Before each test method
Second test method
After each test method
After all test methods

This output proves that the setup, teardown, and test methods are run in the correct order. Let's summarize what we learned from this blog post.

If you want to get access to up-to-date material which helps you to work smarter and save time when you are writing tests with JUnit 5, you should take a look at my Introduction to JUnit 5 course. It has 24 lessons, 47 exercises, and 13 quizzes.

Summary

This blog post has taught us four things:

  • A test class is a normal Java class that is either public or package private.
  • Setup and teardown methods must not be private and they must not return anything.
  • A test method is a method that isn't private and doesn't return anything.
  • We should specify the display name of a test class and a test method because this allows us to replace technical names with sentences that make sense.

P.S. You can get the example application of this blog post from Github.

9 comments… add one
  • Anonymous Sep 9, 2017 @ 13:09

    Hi Petri, thank you for the great introduction to jUnit. It's clear and concise, and certainly very helpful to me as the beginner.

    If you don't mind, let me draw your attention to this sentence in the post:
    "The methods annotated with the @BeforeAll or @AfterAll don’t have to be static. This doesn’t belong to..."
    Is there a mistake, shouldn't these annotations be static?

    • Lada Flac Sep 9, 2017 @ 13:13

      I apologize for being impolite in my previous comment and forgetting to sign myself :/
      Regards,
      Lada

    • Petri Sep 9, 2017 @ 13:22

      Hi,

      no worries. I don't think that you were impolite at all. About your question:

      The methods that are annotated with the @BeforeAll and @AfterAll annotations must be static only if you create a new test instance for each test method (this is the default behavior of JUnit 5). However, it is also possible to use a setting that creates a new test instance for each test class. If you use the latter option, the methods annotated with the @BeforeAll and @AfterAll annotations don't have to be static.

      I will update the post because the original sentence is indeed a bit confusing. Thank you for pointing this out!

  • Olivier Sep 10, 2017 @ 0:17

    That was very unhelpful.Everybody knows JUnit4 and thus does not need to be reminded of the basics. What is needed instead is a commentary on the differences between JUnit4 and JUnit5.

    • Petri Sep 10, 2017 @ 8:56

      Hi Olivier,

      It seems that we have a bit different goals (and that's fine). I want to write a tutorial for people who haven't necessarily used JUnit 4. You (obviously) don't need such tutorial. Instead, you could take a look at this blog post that explains how you can migrate from JUnit 4 to JUnit 5.

      By the way, thank you for pointing out that different people have different needs. I will remember this when I create content for people who are familiar with JUnit 4 and want to get started with JUnit 5.

      • Olivier (another one) Mar 20, 2019 @ 9:49

        Thank you for this comprehensive and quick approach of JUnit. Some people indeed need a 'from scratch' presentation.

  • Tine Sep 10, 2017 @ 8:36

    That was a nice intro of JUnit basics. I look forward to one or more posts where you handle all the new elements of JUnit 5.

    • Petri Sep 10, 2017 @ 9:00

      Hi,

      Thank you for your kind words. I really appreciate them. Also, the next posts of this tutorial will describe the new features of JUnit 5 such as nested tests, extensions, and so on.

Leave a Reply