JUnit 5 User Guide
Stefan Bechtold, Sam Brannen, Johannes Link, Matthias Merdes, Marc Philipp,
Christian Stein
Version 5.3.2
Table of Contents
1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
1.1. What is JUnit 5? . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
1.2. Supported Java Versions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
1.3. Getting Help . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
2. Installation . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
2.1. Dependency Metadata . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 1
Ê
2.2. Dependency Diagram . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 3
Ê
2.3. JUnit Jupiter Sample Projects. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Ê
3. Writing Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Ê
3.1. Annotations . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 4
Ê
3.2. Test Classes and Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 6
Ê
3.3. Display Names . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Ê
3.4. Assertions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 8
Ê
3.5. Assumptions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
Ê
3.6. Disabling Tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
Ê
3.7. Conditional Test Execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 15
Ê
3.8. Tagging and Filtering. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 20
Ê
3.9. Test Instance Lifecycle . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 21
Ê
3.10. Nested Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 22
Ê
3.11. Dependency Injection for Constructors and Methods. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 24
Ê
3.12. Test Interfaces and Default Methods . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
Ê
3.13. Repeated Tests. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 32
Ê
3.14. Parameterized Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 35
Ê
3.15. Test Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Ê
3.16. Dynamic Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 49
Ê
3.17. Parallel Execution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 53
Ê
4. Running Tests . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 55
Ê
4.1. IDE Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 56
Ê
4.2. Build Support. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 57
Ê
4.3. Console Launcher . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 64
Ê
4.4. Using JUnit 4 to run the JUnit Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 68
Ê
4.5. Configuration Parameters . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Ê
4.6. Tag Expressions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 71
Ê
4.7. Capturing Standard Output/Error . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Ê
5. Extension Model . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Ê
5.1. Overview . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Ê
5.2. Registering Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 72
Ê
5.3. Conditional Test Execution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 77
Ê
5.4. Test Instance Factories . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Ê
5.5. Test Instance Post-processing . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Ê
5.6. Parameter Resolution . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 78
Ê
5.7. Test Lifecycle Callbacks. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 79
Ê
5.8. Exception Handling . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 81
Ê
5.9. Providing Invocation Contexts for Test Templates . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 82
Ê
5.10. Keeping State in Extensions. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Ê
5.11. Supported Utilities in Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 84
Ê
5.12. Relative Execution Order of User Code and Extensions . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 85
Ê
6. Migrating from JUnit 4 . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Ê
6.1. Running JUnit 4 Tests on the JUnit Platform . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Ê
6.2. Migration Tips . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 87
Ê
6.3. Limited JUnit 4 Rule Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 88
Ê
7. Advanced Topics. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Ê
7.1. JUnit Platform Launcher API . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 89
Ê
8. API Evolution. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Ê
8.1. API Version and Status . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 92
Ê
8.2. Experimental APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 93
Ê
8.3. Deprecated APIs . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Ê
8.4. @API Tooling Support . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Ê
9. Contributors . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Ê
10. Release Notes. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 95
Ê
1. Overview
The goal of this document is to provide comprehensive reference documentation for programmers
writing tests, extension authors, and engine authors as well as build tool and IDE vendors.
!
Translations
This document is also available in Simplified Chinese and Japanese.
1.1. What is JUnit 5?
Unlike previous versions of JUnit, JUnit 5 is composed of several different modules from three
different sub-projects.
JUnit 5 = JUnit Platform + JUnit Jupiter + JUnit Vintage
The JUnit Platform serves as a foundation for launching testing frameworks on the JVM. It also
defines the TestEngine API for developing a testing framework that runs on the platform.
Furthermore, the platform provides a Console Launcher to launch the platform from the command
line and build plugins for Gradle and Maven as well as a JUnit 4 based Runner for running any
TestEngine on the platform.
JUnit Jupiter is the combination of the new programming model and extension model for writing
tests and extensions in JUnit 5. The Jupiter sub-project provides a TestEngine for running Jupiter
based tests on the platform.
JUnit Vintage provides a TestEngine for running JUnit 3 and JUnit 4 based tests on the platform.
1.2. Supported Java Versions
JUnit 5 requires Java 8 (or higher) at runtime. However, you can still test code that has been
compiled with previous versions of the JDK.
1.3. Getting Help
Ask JUnit 5 related questions on Stack Overflow or chat with us on Gitter.
2. Installation
Artifacts for final releases and milestones are deployed to Maven Central.
Snapshot artifacts are deployed to SonatypeÕs snapshots repository under /org/junit.
2.1. Dependency Metadata
1
2.1.1. JUnit Platform
¥ Group ID: org.junit.platform
¥ Version: 1.3.2
¥ Artifact IDs:
junit-platform-commons
Internal common library/utilities of JUnit. These utilities are intended solely for usage within
the JUnit framework itself. Any usage by external parties is not supported. Use at your own
risk!
junit-platform-console
Support for discovering and executing tests on the JUnit Platform from the console. See
Console Launcher for details.
junit-platform-console-standalone
An executable JAR with all dependencies included is provided at Maven Central under the
junit-platform-console-standalone directory. See Console Launcher for details.
junit-platform-engine
Public API for test engines. See Plugging in your own Test Engine for details.
junit-platform-launcher
Public API for configuring and launching test plans!Ñ!typically used by IDEs and build tools.
See JUnit Platform Launcher API for details.
junit-platform-runner
Runner for executing tests and test suites on the JUnit Platform in a JUnit 4 environment. See
Using JUnit 4 to run the JUnit Platform for details.
junit-platform-suite-api
Annotations for configuring test suites on the JUnit Platform. Supported by the JUnitPlatform
runner and possibly by third-party TestEngine implementations.
junit-platform-surefire-provider
Support for discovering and executing tests on the JUnit Platform using Maven Surefire.
2.1.2. JUnit Jupiter
¥ Group ID: org.junit.jupiter
¥ Version: 5.3.2
¥ Artifact IDs:
junit-jupiter-api
JUnit Jupiter API for writing tests and extensions.
junit-jupiter-engine
JUnit Jupiter test engine implementation, only required at runtime.
2
junit-jupiter-params
Support for parameterized tests in JUnit Jupiter.
junit-jupiter-migrationsupport
Migration support from JUnit 4 to JUnit Jupiter, only required for running selected JUnit 4
rules.
2.1.3. JUnit Vintage
¥ Group ID: org.junit.vintage
¥ Version: 5.3.2
¥ Artifact ID:
junit-vintage-engine
JUnit Vintage test engine implementation that allows to run vintage JUnit tests, i.e. tests
written in the JUnit 3 or JUnit 4 style, on the new JUnit Platform.
2.1.4. Bill of Materials (BOM)
The Bill of Materials POM provided under the following Maven coordinates can be used to ease
dependency management when referencing multiple of the above artifacts using Maven or Gradle.
¥ Group ID: org.junit
¥ Artifact ID: junit-bom
¥ Version: 5.3.2
2.1.5. Dependencies
All of the above artifacts have a dependency in their published Maven POMs on the following @API
Guardian JAR.
¥ Group ID: org.apiguardian
¥ Artifact ID: apiguardian-api
¥ Version: 1.0.0
In addition, most of the above artifacts have a direct or transitive dependency to the following
OpenTest4J JAR.
¥ Group ID: org.opentest4j
¥ Artifact ID: opentest4j
¥ Version: 1.1.1
2.2. Dependency Diagram
3
org.junit.platform
junit-platform-runner
org.junit.jupiter
junit-jupiter-params
org.apiguardian
junit-platform-surefire-provider
junit-platform-console
org.junit.vintage
junit-jupiter-migrationsupport
junit-jupiter-engine
junit-vintage-engine
junit-jupiter-api
junit:junit
junit-platform-launcher
junit-platform-engine
apiguardian-api
All artifacts except
opentest4j and junit:junit
have a dependency on this
artifact. The edges have
been omitted from this
diagram for the sake of
readability.
junit-platform-suite-api
org.opentest4j
opentest4j
junit-platform-commons
2.3. JUnit Jupiter Sample Projects
The junit5-samples repository hosts a collection of sample projects based on JUnit Jupiter and JUnit
Vintage. YouÕll find the respective build scripts (e.g., build.gradle, pom.xml, etc.) in the projects
below.
¥ For Gradle and Java, check out the junit5-jupiter-starter-gradle project.
¥ For Gradle and Kotlin, check out the junit5-jupiter-starter-gradle-kotlin project.
¥ For Gradle and Groovy, check out the junit5-jupiter-starter-gradle-groovy project.
¥ For Maven, check out the junit5-jupiter-starter-maven project.
¥ For Ant, check out the junit5-jupiter-starter-ant project.
3. Writing Tests
A first test case
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.Test;
class FirstJUnit5Tests {
Ê
Ê
Ê
Ê
@Test
void myFirstTest() {
assertEquals(2, 1 + 1);
}
}
3.1. Annotations
JUnit Jupiter supports the following annotations for configuring tests and extending the framework.
All core annotations are located in the org.junit.jupiter.api package in the junit-jupiter-api
module.
4
Annotation
Description
@Test
Denotes that a method is a test method. Unlike JUnit 4Õs @Test annotation, this
annotation does not declare any attributes, since test extensions in JUnit
Jupiter operate based on their own dedicated annotations. Such methods are
inherited unless they are overridden.
@ParameterizedTest Denotes that a method is a parameterized test. Such methods are inherited
unless they are overridden.
@RepeatedTest
Denotes that a method is a test template for a repeated test. Such methods are
inherited unless they are overridden.
@TestFactory
Denotes that a method is a test factory for dynamic tests. Such methods are
inherited unless they are overridden.
@TestInstance
Used to configure the test instance lifecycle for the annotated test class. Such
annotations are inherited.
@TestTemplate
Denotes that a method is a template for test cases designed to be invoked
multiple times depending on the number of invocation contexts returned by
the registered providers. Such methods are inherited unless they are
overridden.
@DisplayName
Declares a custom display name for the test class or test method. Such
annotations are not inherited.
@BeforeEach
Denotes that the annotated method should be executed before each @Test,
@RepeatedTest, @ParameterizedTest, or @TestFactory method in the current class;
analogous to JUnit 4Õs @Before. Such methods are inherited unless they are
overridden.
@AfterEach
Denotes that the annotated method should be executed after each @Test,
@RepeatedTest, @ParameterizedTest, or @TestFactory method in the current class;
analogous to JUnit 4Õs @After. Such methods are inherited unless they are
overridden.
@BeforeAll
Denotes that the annotated method should be executed before all @Test,
@RepeatedTest, @ParameterizedTest, and @TestFactory methods in the current
class; analogous to JUnit 4Õs @BeforeClass. Such methods are inherited (unless
they are hidden or overridden) and must be static (unless the "per-class" test
instance lifecycle is used).
@AfterAll
Denotes that the annotated method should be executed after all @Test,
@RepeatedTest, @ParameterizedTest, and @TestFactory methods in the current
class; analogous to JUnit 4Õs @AfterClass. Such methods are inherited (unless
they are hidden or overridden) and must be static (unless the "per-class" test
instance lifecycle is used).
@Nested
Denotes that the annotated class is a nested, non-static test class. @BeforeAll
and @AfterAll methods cannot be used directly in a @Nested test class unless
the "per-class" test instance lifecycle is used. Such annotations are not
inherited.
@Tag
Used to declare tags for filtering tests, either at the class or method level;
analogous to test groups in TestNG or Categories in JUnit 4. Such annotations
are inherited at the class level but not at the method level.
@Disabled
Used to disable a test class or test method; analogous to JUnit 4Õs @Ignore. Such
annotations are not inherited.
5
Annotation
Description
@ExtendWith
Used to register custom extensions. Such annotations are inherited.
Methods annotated with @Test, @TestTemplate, @RepeatedTest, @BeforeAll, @AfterAll, @BeforeEach, or
@AfterEach annotations must not return a value.
"
Some annotations may currently be experimental. Consult the table in
Experimental APIs for details.
3.1.1. Meta-Annotations and Composed Annotations
JUnit Jupiter annotations can be used as meta-annotations. That means that you can define your
own composed annotation that will automatically inherit the semantics of its meta-annotations.
For example, instead of copying and pasting @Tag("fast") throughout your code base (see Tagging
and Filtering), you can create a custom composed annotation named @Fast as follows. @Fast can then
be used as a drop-in replacement for @Tag("fast").
import
import
import
import
java.lang.annotation.ElementType;
java.lang.annotation.Retention;
java.lang.annotation.RetentionPolicy;
java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}
3.2. Test Classes and Methods
A test method is any instance method that is directly or meta-annotated with @Test, @RepeatedTest,
@ParameterizedTest, @TestFactory, or @TestTemplate. A test class is any top level or static member
class that contains at least one test method.
6
A standard test class
import static org.junit.jupiter.api.Assertions.fail;
import
import
import
import
import
import
org.junit.jupiter.api.AfterAll;
org.junit.jupiter.api.AfterEach;
org.junit.jupiter.api.BeforeAll;
org.junit.jupiter.api.BeforeEach;
org.junit.jupiter.api.Disabled;
org.junit.jupiter.api.Test;
class StandardTests {
Ê
Ê
Ê
@BeforeAll
static void initAll() {
}
Ê
Ê
Ê
@BeforeEach
void init() {
}
Ê
Ê
Ê
@Test
void succeedingTest() {
}
Ê
Ê
Ê
Ê
@Test
void failingTest() {
fail("a failing test");
}
Ê
Ê
Ê
Ê
Ê
@Test
@Disabled("for demonstration purposes")
void skippedTest() {
// not executed
}
Ê
Ê
Ê
@AfterEach
void tearDown() {
}
Ê
Ê
Ê
@AfterAll
static void tearDownAll() {
}
}
#
Neither test classes nor test methods need to be public.
7
3.3. Display Names
Test classes and test methods can declare custom display names!Ñ!with spaces, special characters,
and even emojis!Ñ!that will be displayed by test runners and test reporting.
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("A special test case")
class DisplayNameDemo {
Ê
Ê
Ê
Ê
@Test
@DisplayName("Custom test name containing spaces")
void testWithDisplayNameContainingSpaces() {
}
Ê
Ê
Ê
Ê
@Test
@DisplayName("!¡!¡"!")
void testWithDisplayNameContainingSpecialCharacters() {
}
Ê
Ê
Ê
Ê
@Test
@DisplayName(""")
void testWithDisplayNameContainingEmoji() {
}
}
3.4. 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.
import
import
import
import
import
import
import
import
import
static
static
static
static
static
static
static
static
static
java.time.Duration.ofMillis;
java.time.Duration.ofMinutes;
org.junit.jupiter.api.Assertions.assertAll;
org.junit.jupiter.api.Assertions.assertEquals;
org.junit.jupiter.api.Assertions.assertNotNull;
org.junit.jupiter.api.Assertions.assertThrows;
org.junit.jupiter.api.Assertions.assertTimeout;
org.junit.jupiter.api.Assertions.assertTimeoutPreemptively;
org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.Test;
class AssertionsDemo {
8
Ê
@Test
Ê
void standardAssertions() {
Ê
assertEquals(2, 2);
Ê
assertEquals(4, 4, "The optional assertion message is now the last parameter.
");
Ê
assertTrue('a' < 'b', () -> "Assertion messages can be lazily evaluated -- "
Ê
+ "to avoid constructing complex messages unnecessarily.");
Ê
}
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
@Test
void groupedAssertions() {
// In a grouped assertion all assertions are executed, and any
// failures will be reported together.
assertAll("person",
() -> assertEquals("John", 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("n"))
);
},
() -> {
// 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() {
}
);
9
Ê
Ê
Ê
Ê
Ê
}
Ê
Ê
Ê
Ê
Ê
Ê
Ê
@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.
Thread.sleep(100);
});
}
Ê
private static String greeting() {
10
Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
throw new IllegalArgumentException("a message");
});
assertEquals("a message", exception.getMessage());
Ê
Ê
return "Hello, World!";
}
}
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.
11
import
import
import
import
import
org.junit.jupiter.api.Test
org.junit.jupiter.api.assertAll
org.junit.jupiter.api.Assertions.assertEquals
org.junit.jupiter.api.Assertions.assertTrue
org.junit.jupiter.api.assertThrows
class AssertionsKotlinDemo {
Ê
Ê
Ê
Ê
Ê
Ê
Ê
@Test
fun `grouped assertions`() {
assertAll("person",
{ assertEquals("John", person.firstName) },
{ assertEquals("Doe", person.lastName) }
)
}
Ê
@Test
Ê
fun `exception testing`() {
Ê
val exception = assertThrows ("Should throw an
exception") {
Ê
throw IllegalArgumentException("a message")
Ê
}
Ê
assertEquals("a message", exception.message)
Ê
}
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
Ê
@Test
fun `assertions from a stream`() {
assertAll(
"people with name starting with J",
people
.stream()
.map {
// This mapping returns Stream<() -> Unit>
{ assertTrue(it.firstName.startsWith("J")) }
}
)
}
Ê
Ê
Ê
Ê
Ê
Ê
Ê
}
@Test
fun `assertions from a collection`() {
assertAll(
"people with last name of Doe",
people.map { { assertEquals("Doe", it.lastName) } }
)
}
12
3.4.1. 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 org.junit.jupiter.api.Test;
class HamcrestAssertionDemo {
Ê
Ê
Ê
Ê
@Test
void assertWithHamcrestMatcher() {
assertThat(2 + 1, is(equalTo(3)));
}
}
Naturally, legacy tests based on the JUnit 4 programming model can continue using
org.junit.Assert#assertThat.
3.5. Assumptions
JUnit Jupiter comes with a subset of the assumption methods that JUnit 4 provides and adds a few
that lend themselves well to being used with Java 8 lambdas. All JUnit Jupiter assumptions are static
methods in the org.junit.jupiter.api.Assumptions class.
13
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assumptions.assumeTrue;
import static org.junit.jupiter.api.Assumptions.assumingThat;
import org.junit.jupiter.api.Test;
class AssumptionsDemo {
Ê
Ê
Ê
Ê
Ê
@Test
void testOnlyOnCiServer() {
assumeTrue("CI".equals(System.getenv("ENV")));
// remainder of test
}
Ê
Ê
Ê
Ê
Ê
Ê
@Test
void testOnlyOnDeveloperWorkstation() {
assumeTrue("DEV".equals(System.getenv("ENV")),
() -> "Aborting test: not on developer workstation");
// remainder of test
}
Ê
Ê
Ê
Ê
Ê
Ê
Ê
@Test
void testInAllEnvironments() {
assumingThat("CI".equals(System.getenv("ENV")),
() -> {
// perform these assertions only on the CI server
assertEquals(2, 2);
});
Ê
Ê
Ê
// perform these assertions in all environments
assertEquals("a string", "a string");
}
}
3.6. Disabling Tests
Entire test classes or individual test methods may be disabled via the @Disabled annotation, via one
of the annotations discussed in Conditional Test Execution, or via a custom ExecutionCondition.
HereÕs a @Disabled test class.
14
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled
class DisabledClassDemo {
Ê
@Test
Ê
void testWillBeSkipped() {
Ê
}
}
And hereÕs a test class that contains a @Disabled test method.
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
class DisabledTestsDemo {
Ê
Ê
Ê
Ê
@Disabled
@Test
void testWillBeSkipped() {
}
Ê
Ê
Ê
}
@Test
void testWillBeExecuted() {
}
3.7. Conditional Test Execution
The ExecutionCondition extension API in JUnit Jupiter allows developers to either enable or disable a
container or test based on certain conditions programmatically. The simplest example of such a
condition is the built-in DisabledCondition which supports the @Disabled annotation (see Disabling
Tests). In addition to @Disabled, JUnit Jupiter also supports several other annotation-based
conditions in the org.junit.jupiter.api.condition package that allow developers to enable or
disable containers and tests declaratively. See the following sections for details.
Composed Annotations
Note that any of the conditional annotations listed in the following sections may
!
also be used as a meta-annotation in order to create a custom composed
annotation. For example, the @TestOnMac annotation in the @EnabledOnOs demo
shows how you can combine @Test and @EnabledOnOs in a single, reusable
annotation.
15
Each of the conditional annotations listed in the following sections can only be
declared once on a given test interface, test class, or test method. If a conditional
"
annotation is directly present, indirectly present, or meta-present multiple times
on a given element, only the first such annotation discovered by JUnit will be used;
any additional declarations will be silently ignored. Note, however, that each
conditional annotation may be used in conjunction with other conditional
annotations in the org.junit.jupiter.api.condition package.
3.7.1. Operating System Conditions
A container or test may be enabled or disabled on a particular operating system via the
@EnabledOnOs and @DisabledOnOs annotations.
@Test
@EnabledOnOs(MAC)
void onlyOnMacOs() {
Ê
// ...
}
@TestOnMac
void testOnMac() {
Ê
// ...
}
@Test
@EnabledOnOs({ LINUX, MAC })
void onLinuxOrMac() {
Ê
// ...
}
@Test
@DisabledOnOs(WINDOWS)
void notOnWindows() {
Ê
// ...
}
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Test
@EnabledOnOs(MAC)
@interface TestOnMac {
}
3.7.2. Java Runtime Environment Conditions
A container or test may be enabled or disabled on a particular version of the Java Runtime
Environment (JRE) via the @EnabledOnJre and @DisabledOnJre annotations.
16
@Test
@EnabledOnJre(JAVA_8)
void onlyOnJava8() {
Ê
// ...
}
@Test
@EnabledOnJre({ JAVA_9, JAVA_10 })
void onJava9Or10() {
Ê
// ...
}
@Test
@DisabledOnJre(JAVA_9)
void notOnJava9() {
Ê
// ...
}
3.7.3. System Property Conditions
A container or test may be enabled or disabled based on the value of the named JVM system property
via the @EnabledIfSystemProperty and @DisabledIfSystemProperty annotations. The value supplied
via the matches attribute will be interpreted as a regular expression.
@Test
@EnabledIfSystemProperty(named = "os.arch", matches = ".*64.*")
void onlyOn64BitArchitectures() {
Ê
// ...
}
@Test
@DisabledIfSystemProperty(named = "ci-server", matches = "true")
void notOnCiServer() {
Ê
// ...
}
3.7.4. Environment Variable Conditions
A container or test may be enabled or disabled based on the value of the named environment
variable from the underlying operating system via the @EnabledIfEnvironmentVariable and
@DisabledIfEnvironmentVariable annotations. The value supplied via the matches attribute will be
interpreted as a regular expression.
17
@Test
@EnabledIfEnvironmentVariable(named = "ENV", matches = "staging-server")
void onlyOnStagingServer() {
Ê
// ...
}
@Test
@DisabledIfEnvironmentVariable(named = "ENV", matches = ".*development.*")
void notOnDeveloperWorkstation() {
Ê
// ...
}
3.7.5. Script-based Conditions
JUnit Jupiter provides the ability to either enable or disable a container or test depending on the
evaluation of a script configured via the @EnabledIf or @DisabledIf annotation. Scripts can be
written in JavaScript, Groovy, or any other scripting language for which there is support for the
Java Scripting API, defined by JSR 223.
"
Conditional test execution via @EnabledIf and @DisabledIf is currently an
experimental feature. Consult the table in Experimental APIs for details.
If the logic of your script depends only on the current operating system, the
!
current Java Runtime Environment version, a particular JVM system property, or a
particular environment variable, you should consider using one of the built-in
annotations dedicated to that purpose. See the previous sections of this chapter for
further details.
#
18
If you find yourself using the same script-based condition many times, consider
writing a dedicated ExecutionCondition extension in order to implement the
condition in a faster, type-safe, and more maintainable manner.
@Test // Static JavaScript expression.
@EnabledIf("2 * 3 == 6")
void willBeExecuted() {
Ê
// ...
}
@RepeatedTest(10) // Dynamic JavaScript expression.
@DisabledIf("Math.random() < 0.314159")
void mightNotBeExecuted() {
Ê
// ...
}
@Test // Regular expression testing bound system property.
@DisabledIf("/32/.test(systemProperty.get('os.arch'))")
void disabledOn32BitArchitectures() {
Ê
assertFalse(System.getProperty("os.arch").contains("32"));
}
@Test
@EnabledIf("'CI' == systemEnvironment.get('ENV')")
void onlyOnCiServer() {
Ê
assertTrue("CI".equals(System.getenv("ENV")));
}
@Test // Multi-line script, custom engine name and custom reason.
@EnabledIf(value = {
Ê
"load('nashorn:mozilla_compat.js')",
Ê
"importPackage(java.time)",
Ê
"",
Ê
"var today = LocalDate.now()",
Ê
"var tomorrow = today.plusDays(1)",
Ê
"tomorrow.isAfter(today)"
Ê
},
Ê
engine = "nashorn",
Ê
reason = "Self-fulfilling: {result}")
void theDayAfterTomorrow() {
Ê
LocalDate today = LocalDate.now();
Ê
LocalDate tomorrow = today.plusDays(1);
Ê
assertTrue(tomorrow.isAfter(today));
}
Script Bindings
The following names are bound to each script context and therefore usable within the script. An
accessor provides access to a map-like structure via a simple String get(String name) method.
Name
Type
Description
systemEnvironment
accessor
Operating system environment variable accessor.
19
Name
Type
Description
systemProperty
accessor
JVM system property accessor.
junitConfiguration accessor
Parameter
Configuration parameter accessor.
junitDisplayName
String
Display name of the test or container.
junitTags
Set
All tags assigned to the test or container.
junitUniqueId
String
Unique ID of the test or container.
3.8. Tagging and Filtering
Test classes and methods can be tagged via the @Tag annotation. Those tags can later be used to
filter test discovery and execution.
3.8.1. Syntax Rules for Tags
¥ A tag must not be null or blank.
¥ A trimmed tag must not contain whitespace.
¥ A trimmed tag must not contain ISO control characters.
¥ A trimmed tag must not contain any of the following reserved characters.
" ,: comma
" (: left parenthesis
" ): right parenthesis
" &: ampersand
" |: vertical bar
" !: exclamation point
#
In the above context, "trimmed" means that leading and trailing whitespace
characters have been removed.
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Tag("fast")
@Tag("model")
class TaggingDemo {
Ê
Ê
Ê
Ê
}
20
@Test
@Tag("taxes")
void testingTaxCalculation() {
}
3.9. Test Instance Lifecycle
In order to allow individual test methods to be executed in isolation and to avoid unexpected side
effects due to mutable test instance state, JUnit creates a new instance of each test class before
executing each test method (see Test Classes and Methods). This "per-method" test instance lifecycle
is the default behavior in JUnit Jupiter and is analogous to all previous versions of JUnit.
#
Please note that the test class will still be instantiated if a given test method is
disabled via a condition (e.g., @Disabled, @DisabledOnOs, etc.) even when the "permethod" test instance lifecycle mode is active.
If you would prefer that JUnit Jupiter execute all test methods on the same test instance, simply
annotate your test class with @TestInstance(Lifecycle.PER_CLASS). When using this mode, a new test
instance will be created once per test class. Thus, if your test methods rely on state stored in
instance variables, you may need to reset that state in @BeforeEach or @AfterEach methods.
The "per-class" mode has some additional benefits over the default "per-method" mode. Specifically,
with the "per-class" mode it becomes possible to declare @BeforeAll and @AfterAll on non-static
methods as well as on interface default methods. The "per-class" mode therefore also makes it
possible to use @BeforeAll and @AfterAll methods in @Nested test classes.
If you are authoring tests using the Kotlin programming language, you may also find it easier to
implement @BeforeAll and @AfterAll methods by switching to the "per-class" test instance lifecycle
mode.
3.9.1. Changing the Default Test Instance Lifecycle
If a test class or test interface is not annotated with @TestInstance, JUnit Jupiter will use a default
lifecycle mode. The standard default mode is PER_METHOD; however, it is possible to change the
default for the execution of an entire test plan. To change the default test instance lifecycle mode,
simply set the junit.jupiter.testinstance.lifecycle.default configuration parameter to the name
of an enum constant defined in TestInstance.Lifecycle, ignoring case. This can be supplied as a
JVM system property, as a configuration parameter in the LauncherDiscoveryRequest that is passed to
the Launcher, or via the JUnit Platform configuration file (see Configuration Parameters for details).
For example, to set the default test instance lifecycle mode to Lifecycle.PER_CLASS, you can start
your JVM with the following system property.
-Djunit.jupiter.testinstance.lifecycle.default=per_class
Note, however, that setting the default test instance lifecycle mode via the JUnit Platform
configuration file is a more robust solution since the configuration file can be checked into a
version control system along with your project and can therefore be used within IDEs and your
build software.
To set the default test instance lifecycle mode to Lifecycle.PER_CLASS via the JUnit Platform
configuration file, create a file named junit-platform.properties in the root of the class path (e.g.,
src/test/resources) with the following content.
junit.jupiter.testinstance.lifecycle.default = per_class
21
Changing the default test instance lifecycle mode can lead to unpredictable results
and fragile builds if not applied consistently. For example, if the build configures
"
"per-class" semantics as the default but tests in the IDE are executed using "permethod" semantics, that can make it difficult to debug errors that occur on the
build server. It is therefore recommended to change the default in the JUnit
Platform configuration file instead of via a JVM system property.
3.10. Nested Tests
Nested tests give the test writer more capabilities to express the relationship among several group
of tests. HereÕs an elaborate example.
Nested test suite for testing a stack
import
import
import
import
static
static
static
static
org.junit.jupiter.api.Assertions.assertEquals;
org.junit.jupiter.api.Assertions.assertFalse;
org.junit.jupiter.api.Assertions.assertThrows;
org.junit.jupiter.api.Assertions.assertTrue;
import java.util.EmptyStackException;
import java.util.Stack;
import
import
import
import
org.junit.jupiter.api.BeforeEach;
org.junit.jupiter.api.DisplayName;
org.junit.jupiter.api.Nested;
org.junit.jupiter.api.Test;
@DisplayName("A stack")
class TestingAStackDemo {
Ê
Stack
Source Exif Data:
File Type : PDF
File Type Extension : pdf
MIME Type : application/pdf
PDF Version : 1.4
Linearized : No
Warning : Invalid xref table