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.
What is JUnit?
JUnit is composed of several different modules from three different sub-projects.
JUnit 6.1.3 = 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 the JUnit Platform Suite Engine for running a
custom test suite using one or more test engines on the platform. First-class support for
the JUnit Platform also exists in popular IDEs (see
IntelliJ IDEA,
Eclipse,
NetBeans, and
Visual Studio Code) and build tools (see
Gradle,
Maven,
Ant,
Bazel, and
sbt).
JUnit Jupiter is the combination of the programming model and
extension model for writing JUnit tests and extensions. 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. It requires JUnit 4.12 or later to be present on the class path or module
path. Note, however, that the JUnit Vintage engine is deprecated and should only be used
temporarily while migrating tests to JUnit Jupiter or another testing framework with
native JUnit Platform support.
Supported Java Versions
JUnit requires Java 17 (or higher) at runtime. However, you can still test code that has been compiled with previous versions of the JDK.
Getting Help
Ask JUnit-related questions on Stack Overflow or use the Q&A category on GitHub Discussions.
Getting Started
Downloading JUnit Artifacts
To find out what artifacts are available for download and inclusion in your project, refer to Dependency Metadata. To set up dependency management for your build, refer to Build Support and the Example Projects.
JUnit Features
To find out what features are available in JUnit 6.1.3 and how to use them, read the corresponding sections of this User Guide, organized by topic.
Example Projects
To see complete, working examples of projects that you can copy and experiment with, the
junit-examples repository is a good place to start. The
junit-examples repository hosts a collection of example projects based on JUnit Jupiter,
JUnit Vintage, and other testing frameworks. You’ll find appropriate build scripts (e.g.,
build.gradle, pom.xml, etc.) in the example projects. The links below highlight some
of the combinations you can choose from.
-
For Gradle and Java, check out the
junit-jupiter-starter-gradleproject. -
For Gradle and Kotlin, check out the
junit-jupiter-starter-gradle-kotlinproject. -
For Gradle and Groovy, check out the
junit-jupiter-starter-gradle-groovyproject. -
For Maven, check out the
junit-jupiter-starter-mavenproject. -
For Ant, check out the
junit-jupiter-starter-antproject. -
For Bazel, check out the
junit-jupiter-starter-bazelproject. -
For sbt, check out the
junit-jupiter-starter-sbtproject.
Writing Tests
The following example provides a glimpse at the minimum requirements for writing a test in JUnit Jupiter. Subsequent sections of this chapter will provide further details on all available features.
- Java
-
import static org.junit.jupiter.api.Assertions.assertEquals; import example.util.Calculator; import org.junit.jupiter.api.Test; class MyFirstJUnitJupiterTests { private final Calculator calculator = new Calculator(); @Test void addition() { assertEquals(2, calculator.add(1, 1)); } }
- Kotlin
-
import example.util.Calculator import org.junit.jupiter.api.Assertions.assertEquals import org.junit.jupiter.api.Test class MyFirstJUnitJupiterTests { private val calculator = Calculator() @Test fun addition() { assertEquals(2, calculator.add(1, 1)) } }
Annotations
JUnit Jupiter supports the following annotations for configuring tests and extending the framework.
Unless otherwise stated, all core annotations are located in the org.junit.jupiter.api package
in the junit-jupiter-api module.
@Test-
Denotes that a method is a test method. Unlike JUnit 4’s
@Testannotation, 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.
@TestTemplate-
Denotes that a method is a template for a test case 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.
@TestClassOrder-
Used to configure the test class execution order for
@Nestedtest classes in the annotated test class. Such annotations are inherited. @TestMethodOrder-
Used to configure the test method execution order for the annotated test class; similar to JUnit 4’s
@FixMethodOrder. Such annotations are inherited. @TestInstance-
Used to configure the test instance lifecycle for the annotated test class. Such annotations are inherited.
@DisplayName-
Declares a custom display name for the test class or test method. Such annotations are not inherited.
@DisplayNameGeneration-
Declares a custom display name generator for the test class. Such annotations are inherited.
@BeforeEach-
Denotes that the annotated method should be executed before each
@Test,@RepeatedTest,@ParameterizedTest, or@TestFactorymethod 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@TestFactorymethod 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@TestFactorymethods in the current top-level or@Nestedtest class; analogous to JUnit 4’s@BeforeClass. Such methods are inherited unless they are overridden and must bestaticunless the "per-class" test instance lifecycle is used. @AfterAll-
Denotes that the annotated method should be executed after all
@Test,@RepeatedTest,@ParameterizedTest, and@TestFactorymethods in the current top-level or@Nestedtest class; analogous to JUnit 4’s@AfterClass. Such methods are inherited unless they are overridden and must bestaticunless the "per-class" test instance lifecycle is used. @ParameterizedClass-
Denotes that the annotated class is a parameterized class. Such annotations are inherited.
@BeforeParameterizedClassInvocation-
Denotes that the annotated method should be executed once before each invocation of a parameterized class. Such methods are inherited unless they are overridden.
@AfterParameterizedClassInvocation-
Denotes that the annotated method should be executed once after each invocation of a parameterized class. Such methods are inherited unless they are overridden.
@ClassTemplate-
Denotes that the annotated class is a template for a test class designed to be executed multiple times depending on the number of invocation contexts returned by the registered providers. Such annotations are inherited.
@Nested-
Denotes that the annotated class is a non-static nested test class. 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. @AutoClose-
Denotes that the annotated field represents a resource that will be automatically closed after test execution. Such fields are inherited.
@Timeout-
Used to fail a test, test factory, test template, or lifecycle method if its execution exceeds a given duration. Such annotations are inherited.
@TempDir-
Used to supply a temporary directory via field injection or parameter injection in a test class constructor, lifecycle method, or test method; located in the
org.junit.jupiter.api.iopackage. Such fields are inherited. @ExtendWith-
Used to register extensions declaratively. Such annotations are inherited.
@RegisterExtension-
Used to register extensions programmatically via fields. Such fields are inherited.
| Some annotations may currently be experimental. Consult the table in Experimental APIs for details. |
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").
- Java
-
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.junit.jupiter.api.Tag; @Target({ ElementType.TYPE, ElementType.METHOD }) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") public @interface Fast { }
- Kotlin
-
import org.junit.jupiter.api.Tag @Target(AnnotationTarget.TYPE, AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @Tag("fast") annotation class Fast
The following @Test method demonstrates usage of the @Fast annotation.
- Java
-
@Fast @Test void myFastTest() { // ... }
- Kotlin
-
@Fast @Test fun myFastTest() { // ... }
You can even take that one step further by introducing a custom @FastTest annotation
that can be used as a drop-in replacement for @Tag("fast") and @Test.
- Java
-
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import org.junit.jupiter.api.Tag; import org.junit.jupiter.api.Test; @Target(ElementType.METHOD) @Retention(RetentionPolicy.RUNTIME) @Tag("fast") @Test public @interface FastTest { }
- Kotlin
-
import org.junit.jupiter.api.Tag import org.junit.jupiter.api.Test @Target(AnnotationTarget.FUNCTION) @Retention(AnnotationRetention.RUNTIME) @Tag("fast") @Test annotation class FastTest
JUnit automatically recognizes the following as a @Test method that is tagged with
"fast".
- Java
-
@FastTest void myFastTest() { // ... }
- Kotlin
-
@FastTest fun myFastTest() { // ... }
Definitions
Platform Concepts
- Container
-
a node in the test tree that contains other containers or tests as its children (e.g. a test class).
- Test
-
a node in the test tree that verifies expected behavior when executed (e.g. a
@Testmethod).
Jupiter Concepts
- Lifecycle Method
-
any method that is directly annotated or meta-annotated with
@BeforeAll,@AfterAll,@BeforeEach, or@AfterEach. - Test Class
-
any top-level class,
staticmember class, or@Nestedclass that contains at least one test method, i.e. a container. Test classes must not beabstractand must have a single constructor. Javarecordclasses are supported as well. - Test Method
-
any instance method that is directly annotated or meta-annotated with
@Test,@RepeatedTest,@ParameterizedTest,@TestFactory, or@TestTemplate. With the exception of@Test, these create a container in the test tree that groups tests or, potentially (for@TestFactory), other containers.
Test Classes and Methods
Test methods and lifecycle methods may be declared locally within the current test class,
inherited from superclasses, or inherited from interfaces (see
Test Interfaces and Default Methods). In addition, test methods and
lifecycle methods must not be abstract and must not return a value (except @TestFactory
methods which are required to return a value).
|
Class and method visibility
Test classes, test methods, and lifecycle methods are not required to be It is generally recommended to omit the |
|
Field and method inheritance
Fields in test classes are inherited. For example, a Test methods and lifecycle methods are inherited unless they are overridden according to
the visibility rules of the Java language. For example, a See also: Field and Method Search Semantics |
The following test class demonstrates the use of @Test methods and all supported
lifecycle methods. For further information on runtime semantics, see
Test Execution Order and
Wrapping Behavior of Callbacks.
- Java
-
import static org.junit.jupiter.api.Assertions.fail; import static org.junit.jupiter.api.Assumptions.assumeTrue; import org.junit.jupiter.api.AfterAll; import org.junit.jupiter.api.AfterEach; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Disabled; import 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 } @Test void abortedTest() { assumeTrue("abc".contains("Z")); fail("test should have been aborted"); } @AfterEach void tearDown() { } @AfterAll static void tearDownAll() { } }
- Kotlin
-
import org.junit.jupiter.api.AfterAll import org.junit.jupiter.api.AfterEach import org.junit.jupiter.api.Assumptions.assumeTrue import org.junit.jupiter.api.BeforeAll import org.junit.jupiter.api.BeforeEach import org.junit.jupiter.api.Disabled import org.junit.jupiter.api.Test import org.junit.jupiter.api.fail class StandardTests { @BeforeEach fun init() { } @Test fun succeedingTest() { } @Test fun failingTest() { fail("a failing test") } @Test @Disabled("for demonstration purposes") fun skippedTest() { // not executed } @Test fun abortedTest() { assumeTrue("abc".contains("Z")) fail("test should have been aborted") } @AfterEach fun tearDown() { } companion object { @JvmStatic @BeforeAll fun initAll() { } @JvmStatic @AfterAll fun tearDownAll() { } } }
It is also possible to use Java record classes as test classes as illustrated by the
following example.
import static org.junit.jupiter.api.Assertions.assertEquals;
import example.util.Calculator;
import org.junit.jupiter.api.Test;
record MyFirstJUnitJupiterRecordTests() {
@Test
void addition() {
assertEquals(2, new Calculator().add(1, 1));
}
}
Kotlin Coroutines
Test methods and lifecycle methods may be written in Kotlin and may optionally use the suspend
keyword for testing code using coroutines.
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
class KotlinCoroutinesDemo {
@BeforeEach
fun regularSetUp() {
}
@BeforeEach
suspend fun coroutineSetUp() {
}
@Test
fun regularTest() {
}
@Test
suspend fun coroutineTest() {
}
}
Using suspending functions as test or lifecycle methods requires
kotlin-stdlib,
kotlin-reflect,
and
kotlinx-coroutines-core
to be present on the classpath or module path.
|
When using suspend test or lifecycle methods, JUnit internally uses runBlocking to execute them.
This is sufficient for simple coroutine-based tests.
However, runBlocking does not support skipping calls to delay and does not provide control over
virtual time or dispatchers.
As an alternative, tests can be written as regular @Test methods and wrapped in runTest from