There is a newer version available.
For the latest stable version, please use JUnit 6.0.1!

Assertions

JUnit Jupiter comes with many of the assertion methods that JUnit 4 has and adds a few that lend themselves well to being used with Java 8 lambdas. All JUnit Jupiter assertions are static methods in the org.junit.jupiter.api.Assertions class.

Assertion methods optionally accept the assertion message as their third parameter, which can be either a String or a Supplier<String>.

When using a Supplier<String> (e.g., a lambda expression), the message is evaluated lazily. This can provide a performance benefit, especially if message construction is complex or time-consuming, as it is only evaluated when the assertion fails.

import static java.time.Duration.ofMillis;
import static java.time.Duration.ofMinutes;
import static org.junit.jupiter.api.Assertions.assertAll;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertThrows;
import static org.junit.jupiter.api.Assertions.assertTimeout;
import static org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
import static org.junit.jupiter.api.Assertions.assertTrue;

import java.util.concurrent.CountDownLatch;

import example.domain.Person;
import example.util.Calculator;

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

class AssertionsDemo {

	private final Calculator calculator = new Calculator();

	private final Person person = new Person("Jane", "Doe");

	@Test
	void standardAssertions() {
		assertEquals(2, calculator.add(1, 1));
		assertEquals(4, calculator.multiply(2, 2),
				"The optional failure message is now the last parameter");

		// Lazily evaluates generateFailureMessage('a','b').
		assertTrue('a' < 'b', () -> generateFailureMessage('a','b'));
	}

	@Test
	void groupedAssertions() {
		// In a grouped assertion all assertions are executed, and all
		// failures will be reported together.
		assertAll("person",
			() -> assertEquals("Jane", person.getFirstName()),
			() -> assertEquals("Doe", person.getLastName())
		);
	}

	@Test
	void dependentAssertions() {
		// Within a code block, if an assertion fails the
		// subsequent code in the same block will be skipped.
		assertAll("properties",
			() -> {
				String firstName = person.getFirstName();
				assertNotNull(firstName);

				// Executed only if the previous assertion is valid.
				assertAll("first name",
					() -> assertTrue(firstName.startsWith("J")),
					() -> assertTrue(firstName.endsWith("e"))
				);
			},
			() -> {
				// Grouped assertion, so processed independently
				// of results of first name assertions.
				String lastName = person.getLastName();
				assertNotNull(lastName);

				// Executed only if the previous assertion is valid.
				assertAll("last name",
					() -> assertTrue(lastName.startsWith("D")),
					() -> assertTrue(lastName.endsWith("e"))
				);
			}
		);
	}

	@Test
	void exceptionTesting() {
		Exception exception = assertThrows(ArithmeticException.class, () ->
			calculator.divide(1, 0));
		assertEquals("/ by zero", exception.getMessage());
	}

	@Test
	void timeoutNotExceeded() {
		// The following assertion succeeds.
		assertTimeout(ofMinutes(2), () -> {
			// Perform task that takes less than 2 minutes.
		});
	}

	@Test
	void timeoutNotExceededWithResult() {
		// The following assertion succeeds, and returns the supplied object.
		String actualResult = assertTimeout(ofMinutes(2), () -> {
			return "a result";
		});
		assertEquals("a result", actualResult);
	}

	@Test
	void timeoutNotExceededWithMethod() {
		// The following assertion invokes a method reference and returns an object.
		String actualGreeting = assertTimeout(ofMinutes(2), AssertionsDemo::greeting);
		assertEquals("Hello, World!", actualGreeting);
	}

	@Test
	void timeoutExceeded() {
		// The following assertion fails with an error message similar to:
		// execution exceeded timeout of 10 ms by 91 ms
		assertTimeout(ofMillis(10), () -> {
			// Simulate task that takes more than 10 ms.
			Thread.sleep(100);
		});
	}

	@Test
	void timeoutExceededWithPreemptiveTermination() {
		// The following assertion fails with an error message similar to:
		// execution timed out after 10 ms
		assertTimeoutPreemptively(ofMillis(10), () -> {
			// Simulate task that takes more than 10 ms.
			new CountDownLatch(1).await();
		});
	}

	private static String greeting() {
		return "Hello, World!";
	}

	private static String generateFailureMessage(char a, char b) {
		return "Assertion messages can be lazily evaluated -- "
				+ "to avoid constructing complex messages unnecessarily." + (a < b);
	}
}
Preemptive Timeouts with assertTimeoutPreemptively()

The various assertTimeoutPreemptively() methods in the Assertions class execute the provided executable or supplier in a different thread than that of the calling code. This behavior can lead to undesirable side effects if the code that is executed within the executable or supplier relies on java.lang.ThreadLocal storage.

One common example of this is the transactional testing support in the Spring Framework. Specifically, Spring’s testing support binds transaction state to the current thread (via a ThreadLocal) before a test method is invoked. Consequently, if an executable or supplier provided to assertTimeoutPreemptively() invokes Spring-managed components that participate in transactions, any actions taken by those components will not be rolled back with the test-managed transaction. On the contrary, such actions will be committed to the persistent store (e.g., relational database) even though the test-managed transaction is rolled back.

Similar side effects may be encountered with other frameworks that rely on ThreadLocal storage.

Kotlin Assertion Support

JUnit Jupiter also comes with a few assertion methods that lend themselves well to being used in Kotlin. All JUnit Jupiter Kotlin assertions are top-level functions in the org.junit.jupiter.api package.

import example.domain.Person
import example.util.Calculator
import org.junit.jupiter.api.Assertions.assertEquals
import org.junit.jupiter.api.Assertions.assertTrue
import org.junit.jupiter.api.Tag
import org.junit.jupiter.api.Test
import org.junit.jupiter.api.assertAll
import org.junit.jupiter.api.assertDoesNotThrow
import org.junit.jupiter.api.assertInstanceOf
import org.junit.jupiter.api.assertNotNull
import org.junit.jupiter.api.assertThrows
import org.junit.jupiter.api.assertTimeout
import org.junit.jupiter.api.assertTimeoutPreemptively
import java.time.Duration

class KotlinAssertionsDemo {
    private val person = Person("Jane", "Doe")
    private val people = setOf(person, Person("John", "Doe"))

    @Test
    fun `exception absence testing`() {
        val calculator = Calculator()
        val result =
            assertDoesNotThrow("Should not throw an exception") {
                calculator.divide(0, 1)
            }
        assertEquals(0, result)
    }

    @Test
    fun `expected exception testing`() {
        val calculator = Calculator()
        val exception =
            assertThrows<ArithmeticException> ("Should throw an exception") {
                calculator.divide(1, 0)
            }
        assertEquals("/ by zero", exception.message)
    }

    @Test
    fun `grouped assertions`() {
        assertAll(
            "Person properties",
            { assertEquals("Jane", person.firstName) },
            { assertEquals("Doe", person.lastName) }
        )
    }

    @Test
    fun `grouped assertions from a stream`() {
        assertAll(
            "People with first name starting with J",
            people
                .stream()
                .map {
                    // This mapping returns Stream<() -> Unit>
                    { assertTrue(it.firstName.startsWith("J")) }
                }
        )
    }

    @Test
    fun `grouped assertions from a collection`() {
        assertAll(
            "People with last name of Doe",
            people.map { { assertEquals("Doe", it.lastName) } }
        )
    }

    @Test
    fun `timeout not exceeded testing`() {
        val fibonacciCalculator = FibonacciCalculator()
        val result =
            assertTimeout(Duration.ofMillis(1000)) {
                fibonacciCalculator.fib(14)
            }
        assertEquals(377, result)
    }

    @Test
    fun `timeout exceeded with preemptive termination`() {
        // The following assertion fails with an error message similar to:
        // execution timed out after 10 ms
        assertTimeoutPreemptively(Duration.ofMillis(10)) {
            // Simulate task that takes more than 10 ms.
            Thread.sleep(100)
        }
    }

    @Test
    fun `assertNotNull with a smart cast`() {
        val nullablePerson: Person? = person

        assertNotNull(nullablePerson)

        // The compiler smart casts nullablePerson to a non-nullable object.
        // The safe call operator (?.) isn't required.
        assertEquals(person.firstName, nullablePerson.firstName)
        assertEquals(person.lastName, nullablePerson.lastName)
    }

    @Test
    fun `assertInstanceOf with a smart cast`() {
        val maybePerson: Any = person

        assertInstanceOf<Person>(maybePerson)

        // The compiler smart casts maybePerson to a Person object,
        // allowing to access the Person properties.
        assertEquals(person.firstName, maybePerson.firstName)
        assertEquals(person.lastName, maybePerson.lastName)
    }
}

Third-party Assertion Libraries

Even though the assertion facilities provided by JUnit Jupiter are sufficient for many testing scenarios, there are times when more power and additional functionality such as matchers are desired or required. In such cases, the JUnit team recommends the use of third-party assertion libraries such as AssertJ, Hamcrest, Truth, etc. Developers are therefore free to use the assertion library of their choice.

For example, the combination of matchers and a fluent API can be used to make assertions more descriptive and readable. However, JUnit Jupiter’s org.junit.jupiter.api.Assertions class does not provide an assertThat() method like the one found in JUnit 4’s org.junit.Assert class which accepts a Hamcrest Matcher. Instead, developers are encouraged to use the built-in support for matchers provided by third-party assertion libraries.

The following example demonstrates how to use the assertThat() support from Hamcrest in a JUnit Jupiter test. As long as the Hamcrest library has been added to the classpath, you can statically import methods such as assertThat(), is(), and equalTo() and then use them in tests like in the assertWithHamcrestMatcher() method below.

import static org.hamcrest.CoreMatchers.equalTo;
import static org.hamcrest.CoreMatchers.is;
import static org.hamcrest.MatcherAssert.assertThat;

import example.util.Calculator;

import org.junit.jupiter.api.Test;

class HamcrestAssertionsDemo {

	private final Calculator calculator = new Calculator();

	@Test
	void assertWithHamcrestMatcher() {
		assertThat(calculator.subtract(4, 1), is(equalTo(3)));
	}

}

Naturally, legacy tests based on the JUnit 4 programming model can continue using org.junit.Assert#assertThat.