[EN] JUnit 5 Basics

Julian | Jul 25, 2024 min read

JUnit 5 is the latest version of the popular testing framework for Java. It offers a variety of features to help you test your applications. To give you as a beginner the most important 20% of insights that will help you understand and apply 80% of JUnit 5 usage, we will focus on the basic and commonly used features.

1. Basics and Installation

JUnit 5 consists of three main components:

  • JUnit Platform: The basis for launching test frameworks on the JVM.
  • JUnit Jupiter: The new programming interface and extension model of JUnit 5.
  • JUnit Vintage: Allows you to run JUnit 3 and JUnit 4 tests.

To use JUnit 5 in a Maven project, add the following dependencies to your pom.xml:

<dependency>
    <groupId>org.junit.jupiter</groupId>
    <artifactId>junit-jupiter-engine</artifactId>
    <version>5.10.3</version>
    <scope>test</scope>
</dependency>

For Gradle users:

testImplementation 'org.junit.jupiter:junit-jupiter-engine:5.10.3'

2. Basic Annotation

Here are the most important annotations you should know:

  • @Test: Marks a method as a test method.
  • @BeforeEach: Executes a method before each test.
  • @AfterEach: Executes a method after each test.
  • @BeforeAll: Executes a method once before all tests (must be static).
  • @AfterAll: Executes a method once after all tests (must be static).

Example:

import org.junit.jupiter.api.*;

public class MyFirstJUnit5Tests {

    @BeforeAll
    static void initAll() {
        System.out.println("Before all tests");
    }

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

    @Test
    void succeedingTest() {
        Assertions.assertTrue(true);
    }

    @Test
    void failingTest() {
        Assertions.assertTrue(false);
    }

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

    @AfterAll
    static void tearDownAll() {
        System.out.println("After all tests");
    }
}

3. Assertions

Assertions are crucial to verify the results of the tests. Here are the most important assertions:

  • assertEquals(expected, actual): Checks whether two values ​​are equal.
  • assertNotEquals(expected, actual): Checks whether two values ​​are not equal.
  • assertTrue(condition): Checks whether the condition is true.
  • assertFalse(condition): Checks whether the condition is false.
  • assertNull(value): Checks whether a DayOfWeek is null.
  • assertNotNull(value): Checks whether a DayOfWeek is not null.
  • assertThrows(expectedType, executable): Checks whether a specific exception is thrown.

Example:

import org.junit.jupiter.api.Assertions;
import org.junit.jupiter.api.Test;

public class AssertionTests {

    @Test
    void testAssertions() {
        Assertions.assertEquals(4, 2 + 2);
        Assertions.assertNotEquals(5, 2 + 2);
        Assertions.assertTrue(3 > 2);
        Assertions.assertFalse(3 < 2);
        Assertions.assertNull(null);
        Assertions.assertNotNull(new Object());
        Assertions.assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException();
        });
    }
}

4. Parameterized Tests

JUnit 5 makes it possible to run tests with various parameters. This is particularly useful when you want to test a method with different inputs.

Example:

import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;

public class ParameterizedTests {

    @ParameterizedTest
    @ValueSource(strings = { "racecar", "radar", "madam" })
    void palindromeTest(String word) {
        Assertions.assertTrue(isPalindrome(word));
    }

    boolean isPalindrome(String word) {
        return word.equals(new StringBuilder(word).reverse().toString());
    }
}

5. The @DisplayName annotation

You can use @DisplayName to specify a custom name for your test. This will be displayed in the test reports.

Example:

import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;

@DisplayName("Test class demonstrating @DisplayName annotation")
public class DisplayNameTests {

    @Test
    @DisplayName("Test for the successful case")
    void successfulTest() {
        Assertions.assertTrue(true);
    }
}

6. Test Suites

JUnit 5 allows you to create test suites to group multiple test classes together and run them as a group.

Example:

import org.junit.platform.suite.api.IncludeClassNamePatterns;
import org.junit.platform.suite.api.SelectPackages;
import org.junit.platform.suite.api.Suite;

@Suite
@SelectPackages("com.example.tests")
@IncludeClassNamePatterns(".*Test")
public class SuiteTest {}

Summary

Here are the top 20% of insights summarized to help you understand 80% of JUnit 5:

  1. Installation and Configuration: Add the necessary dependencies to your project.
  2. Basic Annotations: Know and apply annotations such as @Test, @BeforeEach, @AfterEach, @BeforeAll and @AfterAll.
  3. Assertions: Using assertions to verify the results of your tests.
  4. Parameterized Tests: Using parameterized tests to test methods with different inputs.
  5. @DisplayName: Use the @DisplayName annotation for custom test names.
  6. Test Suites: Create and execute test suites for grouped test executions.

With this knowledge, you should be able to use JUnit 5 effectively and lay a solid foundation for testing your Java applications. Good luck with testing! 🚀