*}

JUnit 5: Quick start guide

JUnit 5 enables many different styles of testing and focuses on Java 8 and above. In this article I will show you how to start with new version of JUnit.

|

Introduction

JUnit is a great unit testing framework for the Java programming language. However, version 4 of the framework has a few disadvantages like multiple runners problem or lack of dependent tests, which make it inconvenient for programmers to create integration tests.

The JUnit 5 team published its first General Availability Release on September 10, 2017. JUnit 5 enables many different styles of testing and focuses on Java 8 and above. In this article I will show you how to start with new version of JUnit. I assume that you are similar with JUnit 4.12, Java 8 and Maven.

Overview of Junit 5

JUnit 5 is composed of several different modules from three different sub-projects:

  • JUnit Platform is responsible for launching testing frameworks on the JVM. It defines the TestEngine API for developing a testing framework that runs on the platform. It is an interface between JUnit and its client such as build tools.
  • JUnit Jupiter provides a TestEngine for running Jupiter based tests on the platform.
  • JUnit Vintage enables running JUnit 3 and JUnit 4 based tests on the Junit 5 platform.

Junit 5 installation

To run your first test with Junit 5 you need to add the following dependency to your pom.xml file:

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

It is worth mentioning that JUnit 5 requires Java 8 (or higher) at runtime.

Annotation changes

JUnit 5 comes with important changes within its annotations:

  • @Before annotation is renamed to @BeforeEach
  • @After annotation is renamed to @AfterEach
  • @BeforeClass annotation is renamed to @BeforeAll
  • @AfterClass annotation is renamed to @AfterAll
  • @Ignore annotation is renamed to @Disabled

Assertions and assumptions

JUnit 5 adds a few assertions that lend themselves well to being used with Java 8 lambdas. Method assertAll() can execute all assertions regardless of its results:

@Test
void shouldAddTwoPositiveNumbers() {
    assertAll(
            () -> assertEquals(4, calculator.add(2, 2)),
            () -> assertEquals(6, calculator.add(3, 3))
    );
}

The expected parameter was removed from @Test annotation. We can still use @Rule mechanism to check if tested method throws exception. However, there is a new possibility to test it. Method assertThrows is able to check which particular line of test causes exception:

@Test
void shouldThrowExceptionWhenDivideByZero() {
    Throwable ex = assertThrows(IllegalArgumentException.class,
            () -> calculator.divide(2, 0));
    assertEquals("Cannot divide by zero", ex.getMessage());
}

Another parameter removed from @Test annotation is timeout which was able to control time of test execution. The better way to measure time of tested method execution are assertTimeout and assertTimeoutPreemptively assertions introduced in JUnit 5. The first one waits until the tested method finishes and fails in case of exceeding given timeout. The message of failed assertion describe how much time execution exceeded timeout. The assertTimeoutPreemptively assertion fails instantly when timeout is reached.

@Test
void shouldExecuteWithin10ms_waitForCompletion() {
    assertTimeout(ofMillis(10),
            () -> calculator.add(123, 456));
}

@Test
void shouldExecuteWithin10ms_failIfExceeded() {
    assertTimeoutPreemptively(ofMillis(10),
            () -> calculator.add(321, 654));
}

 JUnit 5 does not provide an assertThat() method which accepts a Hamcrest Matcher like the one found in previous versions. Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries such as AssertJ, Hamcrest, Truth, etc.

 Assumptions are similar to assertions, except that assumptions must hold true or the test will be aborted. Assumptions are used to run tests only if certain conditions are met.

@Test
void runOnWindows7Only() {
    assumeTrue("Windows 7".equals(System.getProperty("os.name")));
    // Test will be aborted if assumption is not met
    // ...
}

Display Names

Test classes and test methods can declare custom display names  - with spaces and special characters - that will be displayed by test runners and test reporting.

@Test
@DisplayName("2 + 2 addition test")
void testAddition() {
    assertEquals(4, calculator.add(2 , 2));
}

The test report will display name of test instead of name of method which is often too long and not readable:

Summary

I described a basics of JUnit 5. One of the major goals of JUnit 5 is to make future enhancements and evolution of JUnit easier. Current version enables creating more readable and intuitive tests and comes with Java 8 support and many new testing possibilities. In next article I will review new features of JUnit 5 which make it competitive again more powerful TestNG.

Przemysław Sobierajski

Did you like this article?

JUnit 5: Quick start guide