JUnit 5 Tutorials
JUnit 5 is composed of JUnit Platform, JUnit Jupiter and JUnit Vintage. JUnit Platform plays the role to launch testing framework. JUnit Jupiter helps in writing tests and extensions and JUnit Vintage provides backward compatibility. JUnit 5 uses TestEngine
to run Jupiter based tests on the platform. JUnit Vintage provides a TestEngine
to support JUnit 3 and JUnit 4 based tests to run on JUnit 5 platform. Now find the tutorials.
JUnit @Tag + Filter with Maven
On this page we will learn using @Tag
annotation in our JUnit tests. We will also learn filtering test classes and test methods using tags with Maven.
1. JUnit @Tag
annotation is introduced in JUnit 5.
2. A @Tag
is used at test class level as well as test method level.
3. We need to pass a tag name to @Tag
annotation. Tag names are used to filter which tests are included or excluded for a given test plan.
4. The @Tag
is repeatable annotation. It means we can use @Tag
more than one time at method level as well as class level.
5. Tag name should not contain white spaces. Tag name should not contain ISO control characters and reserved characters such as comma, left parenthesis, right parenthesis, ampersand, vertical bar, exclamation point.
6. Tags can be filtered using build file such as Maven and Gradle. IDE can also be used to filter tags while running JUnit tests.
Technologies Used
Find the technologies being used in our example.
1.Java 8
2.JUnit 5.8.1
3.Maven 3.6.5
Using @Tag Annotation
Find the examples to use @Tag
annotation.
Example-1:
MyAppTest1.java
public class MyAppTest1 {
@Tag("feature2")
@Test
void additionTest() {
int sum = 50 + 60;
assertEquals(110, sum);
}
@Tag("integration")
@Tag("feature1")
@Test
void multiplyTest() {
int multi = 15 * 5;
assertEquals(75, multi);
}
}
Example-2:
MyAppTest2.java
@Tag("integration")
@Tag("acceptance")
public class MyAppTest2 {
@Tag("feature1")
@Test
void additionTest() {
int sum = 60 + 40;
assertEquals(100, sum);
}
@Test
void multiplyTest() {
int multi = 20 * 5;
assertEquals(100, multi);
}
}
Filter with Maven
1. Maven provides maven-surefire-plugin
to execute the unit tests of an application. The reports are generated in *.txt and *.xml files. By default these reports are generated in below directory.
${basedir}/target/surefire-reports/
2. We can filter tests by tags or tag expressions. Here we will learn to filter test using Maven. In Maven,
a. To include tags or tag expressions, use <groups>
b. To exclude tags or tag expressions, use <excludedGroups>
Find the sample Maven code.
pom.xml
<properties>
<maven.compiler.source>8</maven.compiler.source>
<maven.compiler.target>8</maven.compiler.target>
</properties>
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
<build>
<plugins>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-surefire-plugin</artifactId>
<version>3.1.2</version>
<configuration>
<groups>integration | feature2</groups>
<excludedGroups>feature1</excludedGroups>
</configuration>
</plugin>
</plugins>
</build>
3. Tag expression can be created using ! , & , | . To adjust operator precedence, use ( and ). JUnit also supports two special expressions i.e. any()
and none()
.
any(): Selects all tests with any tags at all.
none(): Selects all tests without any tags.
feature1 : Selects all tests for ‘feature1’.
integration | feature2 : Selects all tests for 'integration ’ plus all tests for ‘feature2’.
integration & feature2 : Selects all tests for the intersection between ‘integration’ and ‘feature2’.
4. We can run test files using Maven command as following.
a. Run only single test class, for ex. MyAppTest1
mvn -Dtest=MyAppTest1 test
b. Run all test classes.
mvn -Dtest=* test
Find the print screen of the output.
[INFO] ------------------------------------------------------------------------
[INFO] T E S T S
[INFO] ------------------------------------------------------------------------
[INFO] .......................................................
[INFO] .......................................................
[INFO] Results:
[INFO] Tests run: 2, Failures: 0, Reeors: 0, Skipped: 0
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 0.772 s
[INFO] Finished at: 2023-10-17T17:30:49+08:00
[INFO] ------------------------------------------------------------------------
References
Annotation Type Tag
Tagging and Filtering
Running a Single Test
JUnit @Disabled Example
On this page we will learn using JUnit @Disabled
annotation.
1. JUnit @Disabled
annotation is introduced in JUnit 5. The @Disabled
annotation is JUnit Jupiter API.
2. The @Disabled
annotation is used to disable test methods. A disabled test method will not execute in unit test run.
3. The @Disabled
annotation can be used at method level as well as class level.
4. When @Disabled
is used at class level, all the test methods are disabled and they are not executed.
5. When @Disabled
annotation is used at method level, then that method will not execute in test run. For @Disabled
methods, their lifecycle callbacks such as @BeforeEach
method and @AfterEach
method will also not execute.
6. In a test class, if some test methods are annotated with @Disabled
annotation then these test methods will not execute but other test methods will execute normally.
7. The @Disabled
annotation optionally accepts a string data i.e. the description for disabling the test to execute.
@Disabled("Disabled until bug #123 is fixed.")
@Test
void additionTest() {
------
}
8. The @Disabled
annotation helps in documenting and reporting for disabled tests.
@Disabled at Method Level
Here we will disable a test method using @Disabled
annotation. We just have to annotate the test method with @Disabled
. We can optionally pass the reason for disabling this method to this annotation.
MyAppDisabledTest1.java
public class MyAppDisabledTest1 {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@Disabled("Disabled until bug #123 is fixed.")
@Test
void additionTest() {
int sum = 50 + 60;
assertEquals(110, sum);
}
@Test
void multiplyTest() {
int multi = 15 * 5;
assertEquals(75, multi);
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
Find the console output.
Start...multiplyTest()
Finished...multiplyTest()
In above unit test class, additionTest()
will not execute. The @BeforeEach
and @AfterEach
methods for additionTest()
will also not execute.
The multiplyTest
method will execute normally with @BeforeEach
and @AfterEach
methods.
@Disabled at Class Level
Here we will use @Disabled
annotation at class level. Once a class is annotated with @Disabled
annotation, all the test methods of that class are disabled.
MyAppDisabledTest2.java
@Disabled("Disabled until change in User functionality is completed.")
public class MyAppDisabledTest2 {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@Test
void additionTest() {
int sum = 60 + 40;
assertEquals(100, sum);
}
@Test
void multiplyTest() {
int multi = 20 * 5;
assertEquals(100, multi);
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
Find the print screen of the output.
MyAppDisabledTest1
additionTest() ignored
multiplyTest() 10 ms passed
MyAppDisabledTest2
additionTest() ignored
multiplyTest() ignored
Reference
JUnit @RepeatedTest Example
On this page we will learn using JUnit @RepeatedTest
annotation in our application unit test cases.
1. The @RepeatedTest
annotation is introduced in JUnit 5.
2. The @RepeatedTest
annotation denotes that the method annotated with this is test method that should be repeated a specified number of times with a configurable display name.
3. Each invocation of @RepeatedTest
method executes in the same way as a regular @Test
method.
4. Each invocation of @RepeatedTest
method supports for same lifecycle callbacks and extensions as a regular @Test
method such as calling @BeforeEach
and @AfterEach
methods.
5. The repetition info can be accessed by RepetitionInfo
such as current repetition and total number of repetitions. It can also be accessed using placeholders that are {displayName}
, {currentRepetition}
and {totalRepetitions}
.
6. The @RepeatedTest
methods must not be private or static and must return void.
7. The @RepeatedTest
methods may optionally declare parameters to be resolved by ParameterResolver
as we do in @Test
method. We can resolve parameters such as RepetitionInfo
and TestInfo
in @RepeatedTest
methods.
Technologies Used
Find the technologies being used in our example.
1.Java 8
2.JUnit 5.8.1
3.Maven 3.6.3
Maven Dependencies
Find the Maven dependencies.
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Using @RepeatedTest
To create a repeated test method, just annotate the test method with @RepeatedTest
in place of @Test
annotation. We need to pass the number of repetition to @RepeatedTest
.
@RepeatedTest(3)
void repeatedSumTest() {
int sum = 50 + 60;
assertEquals(110, sum);
}
In the above test method, we have passed 3 to @RepeatedTest
annotation. It means, test method will execute 3 times, each with full cycle. Writing test method with @RepeatedTest(3)
is same as writing test method 3 times with @Test
annotation.
The test method with @RepeatedTest
will execute full cycle for every repetition i.e. @BeforeEach
and @AfterEach
methods will be called for each repetition.
MyAppRepeatedTest1.java
public class MyAppRepeatedTest1 {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@RepeatedTest(3)
void repeatedSumTest() {
System.out.println("---Inside repeatedSumTest ---");
int sum = 50 + 60;
assertEquals(110, sum);
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
Console output
Start...repetition 1 of 3
---Inside repeatedSumTest ---
Finished...repetition 1 of 3
Start...repetition 2 of 3
---Inside repeatedSumTest ---
Finished...repetition 2 of 3
Start...repetition 3 of 3
---Inside repeatedSumTest ---
Finished...repetition 3 of 3
The getDisplayName()
method of TestInfo
gives the test display name.
@RepeatedTest
Display Name
The display name for @RepeatedTest
is the display name for every repetition in test result. To set the display name, we use name
attribute of @RepeatedTest
annotation. The @RepeatedTest
has following attributes.
value: The number of repetitions.
name: The display name for each repetition of the repeated test.
Find the code snippet to set a display name.
@RepeatedTest(value = 3, name= RepeatedTest.SHORT_DISPLAY_NAME)
void repeatedSumTest() {
------
}
Find the print screen of the output.
MyAppRepeatedTest1
repeatedSumTest() 22 ms
repetition 1 of 3 passed
repetition 2 of 3 passed
repetition 3 of 3 passed
The SHORT_DISPLAY_NAME
is the default display name for @RepeatedTest
. We can also set name to LONG_DISPLAY_NAME
.
@RepeatedTest(value = 3, name= RepeatedTest.LONG_DISPLAY_NAME)
void repeatedSumTest() {
------
}
Custom Display Name:
For custom display name, JUnit provides following placeholders supported by name
attribute of @RepeatedTest
.
{displayName}: Test name configured by @DisplayName
annotation.
{currentRepetition}: Current repetition count.
{totalRepetitions}: Total repetition count.
Find the examples to use custom display name for @RepeatedTest
methods.
Ex-1: Using {currentRepetition}
and {totalRepetitions}
placeholders.
@RepeatedTest(value = 3, name= "Addition Test: repetition {currentRepetition}/{totalRepetitions}")
void repeatedSumTest() {
------
}
Print screen of the output.
MyAppRepeatedTest2
repeatedSumTest() 22 ms
Addition Test: repetition 1/3 passed
Addition Test: repetition 1/3 passed
Addition Test: repetition 1/3 passed
Ex-2: Using {displayName}
placeholder that takes value configured by @DisplayName
annotation.
@DisplayName("Addition Test")
@RepeatedTest(value = 3, name = "{displayName}: repetition {currentRepetition}/{totalRepetitions}")
void repeatedSumTest() {
------
}
The output display name of above test will be same as the output of ex-1.
The format of SHORT_DISPLAY_NAME
:
"repetition {currentRepetition} of {totalRepetitions}"
The format of LONG_DISPLAY_NAME
:
"{displayName} :: repetition {currentRepetition} of {totalRepetitions}"
Using RepetitionInfo
JUnit provides RepetitionInfo
and TestInfo
to fetch test execution informations. The RepetitionInfo
gives test repetition information such as current repetition and total repetitions. Using TestInfo
, we fetch test execution display name.
To use RepetitionInfo
and TestInfo
, just use them as test method parameters and JUnit will resolve dependency injection.
The RepetitionInfo
has following methods.
getCurrentRepetition(): Returns the current repetition.
getTotalRepetitions(): Returns the total number of repetitions.
Find the sample code.
@RepeatedTest(3)
void repeatedSumTest(RepetitionInfo repetitionInfo, TestInfo testInfo) {
System.out.println("Display name: " + testInfo.getDisplayName());
System.out.println("Current repetition: " + repetitionInfo.getCurrentRepetition());
System.out.println("Total repetition: " + repetitionInfo.getTotalRepetitions());
int sum = 50 + 60;
assertEquals(110, sum);
}
References
Annotation Type RepeatedTest
Interface RepetitionInfo
JUnit 5 Dynamic Tests
This page will walk through JUnit 5 dynamic tests example. Dynamic test is generated at runtime by a factory method that is annotated with @TestFactory
. Dynamic test has been introduced in JUnit 5 Jupiter. @TestFactory
method differs with @Test
method in such a way that @TestFactory
method is not itself a test case but rather a factory for test cases. So we can say that dynamic test is the product of a factory method. @TestFactory
method must not be private or static and must return a Stream
, Collection
, Iterable
, or Iterator
of DynamicNode
instances. DynamicNode
is an abstract class and it has two subclasses DynamicTest
and DynamicContainer
that can be instantiated. DynamicTest
is a test case generated at run time and DynamicContainer
is a container generated at runtime. DynamicTest
instances will run lazily. In the dynamic test lifecycle @BeforeEach
and @AfterEach
methods are executed for the @TestFactory
method but not for each dynamic test. Dynamic tests are useful when we need to run the same set of tests on many different input values. Now find the complete example of JUnit dynamic tests step by step.
Technologies Used
Find the technologies being used in our example.
1.Java 8
2.JUnit 5
3.Maven 3.6.3
4.Idea 2021.2.3
Maven Build File
Find the Maven build file to resolve the JUnit 5 JAR dependencies.
pom.xml
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
DynamicNode
DynamicNode
is the abstract base class for a container or a test case generated at run time. DynamicNode
has two subclasses DynamicTest
and DynamicContainer
that can be instantiated.
DynamicTest: It is a test case generated at run time. It is created using display name and JUnit Executable
functional interface. DynamicTest
instances will be executed lazily. Find the sample code to instantiate DynamicTest
.
DynamicTest.dynamicTest("Test",
() -> assertTrue(number % 2 == 0, "Output will be true"))
DynamicContainer: It is a container generated at run time. It is created using display name and Iterable
or Stream
of instances of DynamicNode
. Find the sample code to instantiate DynamicContainer
.
DynamicContainer.dynamicContainer("Container", Stream.of(
DynamicTest.dynamicTest("Not Null", () -> assertNotNull(utility.getAllUsers())),
DynamicTest.dynamicTest("Not Empty", () -> assertTrue(utility.getAllUsers().isEmpty()))
))
Instantiate DynamicTest
DynamicTest
has a factory method as dynamicTest
to create DynamicTest
instances.
Find the structure of dynamicTest
method from JUnit doc.
public static DynamicTest dynamicTest(String displayName, Executable executable)
We can see that we need to pass display name and instance of JUnit Executable
functional interface in above factory method.
Find the Executable
abstract method structure from JUnit doc.
void execute() throws Throwable;
The above method has no return type and no arguments. We can instantiate Executable
functional interface using lambda expressions, method references, or constructor references.
Find the sample instantiation of Executable
functional interface using lambda expression.
org.junit.jupiter.api.function.Executable exeTest = () -> {
assertTrue(7 > 5, "Result will be true");
};
The above lambda expressions has no return type and no arguments to match execute
method structure of JUnit Executable
functional interface. Now DynamicTest
can be instantiated as following.
DynamicTest dyTest = DynamicTest.dynamicTest("Test", exeTest);
We can also directly pass lambda expression to our dynamicTest
method as following.
DynamicTest dyTest = DynamicTest.dynamicTest("Test ", () -> {
assertTrue(7 > 5, "Result will be true");
});
Now find the sample dynamic test code in which we initialize DynamicTest
using lambda expression and method reference.
a. Dynamic test using lambda expression
@TestFactory
@DisplayName("Dynamic Test using Lambda Expression")
Stream<DynamicTest> evenNumberDynamicTestWithStream() {
return IntStream.of(2, 4, 6)
.mapToObj(number -> DynamicTest.dynamicTest("Number " + number,
() -> assertTrue(number % 2 == 0, "Output will be true")));
}
b. Dynamic test using method reference
@TestFactory
@DisplayName("Dynamic Test using Method Reference")
Collection<DynamicTest> oddEvenDynamicTestWithCollection() {
return Arrays.asList(
DynamicTest.dynamicTest("Even Number Test", TestUtility::evenNumberTest),
DynamicTest.dynamicTest("Odd Number Test", TestUtility::oddNumberTest)
);
}
@TestFactory Annotation
@TestFactory
denotes that the method is test factory for dynamic tests. @TestFactory
method differs with @Test
method in such a way that @TestFactory
method is not itself a test case but rather a factory for test cases. So we can say that dynamic test is the product of a factory method. @TestFactory
method must not be private or static and must return a Stream
, Collection
, Iterable
, or Iterator
of DynamicNode
instances. Find a sample example of @TestFactory
returning Stream
.
@TestFactory
Stream<DynamicTest> dataLengthDynamicTest() {
return Stream.of("ABC", "PQRS", "XYZ")
.map(el -> DynamicTest.dynamicTest("Test: " + el, () -> assertTrue(el.length() > 2)));
}
As we know that DynamicNode
has the subclasses as DynamicTest
and DynamicContainer
. We create our test cases by creating the instances of DynamicTest
. In the above test factory method we are returning a Stream
of instances of DynamicTest
. These test cases as instances of DynamicTest
will execute lazily.
Dynamic Tests with Stream
Stream
has been introduced in Java 8. It is a sequence of elements that supports sequential and parallel aggregate operations. In JUnit dynamic tests, we can use Stream
to contain our all DynamicTest
instances. The @TestFactory
method needs to return Stream
of DynamicTest
type. Find the example.
@TestFactory
@DisplayName("Dynamic Test with Stream")
Stream<DynamicTest> userAvailabilityDynamicTestWithStream() {
TestUtility utility = new TestUtility();
return Stream.of("Krishn", "Arjun", "Bheem")
.map(user -> DynamicTest.dynamicTest("User Test: " + user, () -> {
assertNotNull(utility.getAllUsers());
utility.addUser(user);
assertTrue(utility.getAllUsers().contains(user), "User will exist");
utility.deleteUser(user);
assertFalse(utility.getAllUsers().contains(user), "User will not exist");
}));
}
The number of instances of DynamicTest
will be created as many as the number of elements in Stream
.
Dynamic Tests with Collection
We can use Java Collection
to create JUnit dynamic tests. The @TestFactory
method needs to return Collection
of DynamicTest
type. We need to collect all our DynamicTest
instances and return it.
@TestFactory
@DisplayName("Dynamic Test with Collection")
Collection<DynamicTest> mathDynamicTestWithCollection() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
);
}
Dynamic Tests with Iterable
We can use Java Iterable
to create JUnit dynamic tests. The @TestFactory
method needs to return Iterable
of DynamicTest
type.
@TestFactory
@DisplayName("Dynamic Test with Iterable")
Iterable<DynamicTest> mathDynamicTestWithIterable() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
);
}
Dynamic Tests with Iterator
We can use Java Iterator
to create JUnit dynamic tests. The @TestFactory
method needs to return Iterator
of DynamicTest
type.
@TestFactory
@DisplayName("Dynamic Test with Iterator")
Iterator<DynamicTest> mathDynamicTestWithIterator() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
).iterator();
}
Dynamic Tests with DynamicContainer
DynamicContainer
is the subclass of DynamicNode
. DynamicContainer
is a container generated at run time. It is created using display name and Iterable
or Stream
of instances of DynamicNode
. Find the example.
@TestFactory
@DisplayName("Dynamic Test with Containers")
Stream<DynamicNode> userAvailabilityDynamicTestWithContainers() {
TestUtility utility = new TestUtility();
return Stream.of("Krishn", "Arjun")
.map(user -> DynamicContainer.dynamicContainer("User Container : " + user, Stream.of(
DynamicTest.dynamicTest("Not Null", () -> assertNotNull(utility.getAllUsers())),
DynamicTest.dynamicTest("Not Empty", () -> assertTrue(utility.getAllUsers().isEmpty())),
DynamicContainer.dynamicContainer("Test Properties", Stream.of(
DynamicTest.dynamicTest("Add User", () -> {
utility.addUser(user);
assertTrue(utility.getAllUsers().contains(user), "User will exist");
}),
DynamicTest.dynamicTest("Delete User", () -> {
utility.deleteUser(user);
assertFalse(utility.getAllUsers().contains(user), "User will not exist");
})
))
)));
}
Dynamic Tests with Interface Default Method
We can create dynamic tests with interface defaults methods and can run it by implementing interface in our test class. To create a dynamic test in interface we need to annotate default method with @TestFactory
annotation and return Stream
, Collection
, Iterable
, or Iterator
of DynamicNode
instances. Find the example returning Collection
.
DynamicTestWithInterface.java
public interface DynamicTestWithInterface {
@TestFactory
@DisplayName("Dynamic Test with Interface Default Method")
default Collection<DynamicTest> oddEvenDynamicTestWithDefaultMethod() {
return Arrays.asList(
DynamicTest.dynamicTest("Even Number Test", () -> {
int num = 21;
assertTrue(num % 2 == 1, "Result will be true");
}),
DynamicTest.dynamicTest("Odd Number Test", () -> {
int num = 30;
assertTrue(num % 2 == 0, "Result will be true");
})
);
}
}
@BeforeEach and @AfterEach with @TestFactory
In the dynamic test lifecycle @BeforeEach
and @AfterEach
methods are executed for the @TestFactory
method but not for each dynamic test. The @BeforeEach
method will execute before execution of @TestFactory
method and @AfterEach
method will execute after complete execution of @TestFactory
method. Find the example.
BeforeEachAndAfterEach.java
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.stream.IntStream;
import java.util.stream.Stream;
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.DisplayName;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.TestInfo;
public class BeforeEachAndAfterEach {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@TestFactory
@DisplayName("Dynamic Test")
Stream<DynamicTest> oddNumberDynamicTestWithStream() {
return IntStream.of(3, 5, 7)
.mapToObj(number -> DynamicTest.dynamicTest("Number " + number,
() -> {
System.out.println("Test "+ number);
assertTrue(number % 2 == 1, "Output will be true");
}));
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
}
Output
---Inside initAll---
Start...Dynamic Test
Test 3
Test 5
Test 7
Finished...Dynamic Test
---Inside tearDownAll---
Complete Example
DynamicTestWithInterface.java
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
public interface DynamicTestWithInterface {
@TestFactory
@DisplayName("Dynamic Test with Interface Default Method")
default Collection<DynamicTest> oddEvenDynamicTestWithDefaultMethod() {
return Arrays.asList(
DynamicTest.dynamicTest("Even Number Test", () -> {
int num = 21;
assertTrue(num % 2 == 1, "Result will be true");
}),
DynamicTest.dynamicTest("Odd Number Test", () -> {
int num = 30;
assertTrue(num % 2 == 0, "Result will be true");
})
);
}
}
LifecycleLogger.java
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.TestInfo;
public interface LifecycleLogger {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@BeforeEach
default void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
default void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
}
TestUtility.java
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.ArrayList;
import java.util.List;
public class TestUtility {
List<String> allUsers = new ArrayList<>();
public List<String> getAllUsers() {
return allUsers;
}
public void addUser(String user) {
allUsers.add(user);
}
public void deleteUser(String user) {
allUsers.remove(user);
}
public static void evenNumberTest() {
int num = 30;
assertTrue(num % 2 == 0, "Result will be true");
}
public static void oddNumberTest() {
int num = 21;
assertTrue(num % 2 == 1, "Result will be true");
}
public long multiplyNumbers(int num1, int num2) {
return num1 * num2;
}
public long addNumbers(int num1, int num2) {
return num1 + num2;
}
}
MyDynamicJUnitTests.java
import static org.junit.jupiter.api.Assertions.assertFalse;
import static org.junit.jupiter.api.Assertions.assertNotNull;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.Arrays;
import java.util.Collection;
import java.util.Iterator;
import java.util.stream.IntStream;
import java.util.stream.Stream;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DynamicContainer;
import org.junit.jupiter.api.DynamicNode;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
public class MyDynamicJUnitTests implements DynamicTestWithInterface, LifecycleLogger {
@TestFactory
@DisplayName("Dynamic Test using Lambda Expression")
Stream<DynamicTest> evenNumberDynamicTestWithStream() {
return IntStream.of(2, 4, 6)
.mapToObj(number -> DynamicTest.dynamicTest("Number " + number,
() -> assertTrue(number % 2 == 0, "Output will be true")));
}
@TestFactory
@DisplayName("Dynamic Test using Method Reference")
Collection<DynamicTest> oddEvenDynamicTestWithCollection() {
return Arrays.asList(
DynamicTest.dynamicTest("Even Number Test", TestUtility::evenNumberTest),
DynamicTest.dynamicTest("Odd Number Test", TestUtility::oddNumberTest)
);
}
@TestFactory
@DisplayName("Dynamic Test with Stream")
Stream<DynamicTest> userAvailabilityDynamicTestWithStream() {
TestUtility utility = new TestUtility();
return Stream.of("Krishn", "Arjun", "Bheem")
.map(user -> DynamicTest.dynamicTest("User Test: " + user, () -> {
assertNotNull(utility.getAllUsers());
utility.addUser(user);
assertTrue(utility.getAllUsers().contains(user), "User will exist");
utility.deleteUser(user);
assertFalse(utility.getAllUsers().contains(user), "User will not exist");
}));
}
@TestFactory
@DisplayName("Dynamic Test with Collection")
Collection<DynamicTest> mathDynamicTestWithCollection() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
);
}
@TestFactory
@DisplayName("Dynamic Test with Iterable")
Iterable<DynamicTest> mathDynamicTestWithIterable() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
);
}
@TestFactory
@DisplayName("Dynamic Test with Iterator")
Iterator<DynamicTest> mathDynamicTestWithIterator() {
TestUtility utility = new TestUtility();
return Arrays.asList(
DynamicTest.dynamicTest("Addition Test",
() -> assertTrue(utility.addNumbers(20, 30) == 50, "Output will be true")),
DynamicTest.dynamicTest("Multiplication Test",
() -> assertTrue(utility.multiplyNumbers(9, 5) == 45, "Output will be true"))
).iterator();
}
@TestFactory
@DisplayName("Dynamic Test with Containers")
Stream<DynamicNode> userAvailabilityDynamicTestWithContainers() {
TestUtility utility = new TestUtility();
return Stream.of("Krishn", "Arjun")
.map(user -> DynamicContainer.dynamicContainer("User Container : " + user, Stream.of(
DynamicTest.dynamicTest("Not Null", () -> assertNotNull(utility.getAllUsers())),
DynamicTest.dynamicTest("Not Empty", () -> assertTrue(utility.getAllUsers().isEmpty())),
DynamicContainer.dynamicContainer("Test Properties", Stream.of(
DynamicTest.dynamicTest("Add User", () -> {
utility.addUser(user);
assertTrue(utility.getAllUsers().contains(user), "User will exist");
}),
DynamicTest.dynamicTest("Delete User", () -> {
utility.deleteUser(user);
assertFalse(utility.getAllUsers().contains(user), "User will not exist");
})
))
)));
}
}
To run the example, the source code and import into IDE. To run a test class, right click on the test class -> Run’##.Test’. We will get output in console. If we are using JUnit 4 environment to run JUnit 5 examples then we need to annotate our test class with @RunWith(JUnitPlatform.class)
annotation.
---Inside initAll---
Start...Dynamic Test with Interface Default Method
Finished...Dynamic Test with Interface Default Method
Start...Dynamic Test with Collection
Finished...Dynamic Test with Collection
Start...Dynamic Test using Lambda Expression
Finished...Dynamic Test using Lambda Expression
Start...Dynamic Test using Method Reference
Finished...Dynamic Test using Method Reference
Start...Dynamic Test with Stream
Finished...Dynamic Test with Stream
Start...Dynamic Test with Containers
Finished...Dynamic Test with Containers
Start...Dynamic Test with Iterable
Finished...Dynamic Test with Iterable
Start...Dynamic Test with Iterator
Finished...Dynamic Test with Iterator
---Inside tearDownAll---
Find the print screen of JUnit run.
MyDynamicJUnitTests
Dynamic Test with Interface Default Method
Even Number Test passed
Odd Number Test passed
Dynamic Test with Collection
Addition Test passed
Multiplication Test passed
Dynamic Test using Lambda Expression
Number 2 passed
Number 4 passed
Number 6 passed
Dynamic Test using Method Reference
Even Number Test passed
Odd Number Test passed
Dynamic Test with Stream
User Test: Krishn passed
User Test: Arjun passed
User Test: Bheem passed
Dynamic Test with Containers
User Container : Krishn
Not Null passed
Not Empty passed
Test Properties
Add User passed
Delete User passed
User Container : Arjun
Not Null passed
Not Empty passed
Test Properties
Add User passed
Delete User passed
Dynamic Test with Iterable
Addition Test passed
Multiplication Test passed
Dynamic Test with Iterator
Addition Test passed
Multiplication Test passed
References
JUnit 5 @BeforeAll and @AfterAll Example
This page will walk through JUnit 5 @BeforeAll
and @AfterAll
example. @BeforeAll
and @AfterAll
annotations are analogous to @BeforeClass
and @AfterClass
respectively of JUnit 4. @BeforeAll
and @AfterAll
methods execute before and after respectively of all @Test
, @RepeatedTest
, @ParameterizedTest
, or @TestFactory
methods in current class. It means @BeforeAll
method executes before all test methods in current class and @AfterAll
method executes after all test methods in current class. @BeforeAll
and @AfterAll
methods must be static and must not return a value. But in interface we can create non-static @BeforeAll
and @AfterAll
methods using @TestInstance
annotation and those methods will be default methods. Now find the complete example for @BeforeAll
and @AfterAll
annotations step by step.
Technologies Used
Find the technologies being used in our example.
1.Java 8
2.JUnit 5
3.Maven 3.6.3
4.Idea 2021.2.3
Maven Build File
Find the Maven build file to resolve the JUnit 5 JAR dependencies.
pom.xml
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
Create Method using @BeforeAll and @AfterAll
@BeforeAll
and @AfterAll
methods must be static and must not return a value. Here we will create a test class using @Test
annotation. Find the example.
UsingTestAnnotation.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.BeforeAll;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class UsingTestAnnotation {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
}
Output
---Inside initAll---
---Inside multiplyTest---
---Inside tearDownAll---
Find the sample utility class used in our example.
Utility.java
import java.util.Arrays;
import java.util.List;
public class Utility {
List<String> allUsers = Arrays.asList("Mahesh", "Ram", "Krishn", "Arjun", "Bheem");
public long multiplyNumbers(int num1, int num2) {
return num1 * num2;
}
public long addNumbers(int num1, int num2) {
return num1 + num2;
}
public boolean isUserAvailable(String userName) {
return allUsers.contains(userName);
}
}
@BeforeAll and @AfterAll with @BeforeEach and @AfterEach
@BeforeEach
method executes after @BeforeAll
method. @AfterEach
method executes before @AfterAll
method. @BeforeAll
method executes before all test methods whereas @BeforeEach
method executes before each test method in the current class. @AfterAll
method executes after all test methods whereas @AfterEach
method executes after each test method in the current class. Find the example of @BeforeAll
and @AfterAll
methods with @BeforeEach
and @AfterEach
methods.
WithBeforeEachAfterEach.java
import static org.junit.jupiter.api.Assertions.assertEquals;
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.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
public class WithBeforeEachAfterEach {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
}
Output
---Inside initAll---
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
---Inside tearDownAll---
@BeforeAll and @AfterAll with @Test, @RepeatedTest, @ParameterizedTest and @TestFactory
Here we will use @BeforeAll
and @AfterAll
methods with @Test
, @RepeatedTest
, @ParameterizedTest
, and @TestFactory
methods. We will observe that @BeforeAll
method will execute before all test methods and @AfterAll
method will execute after all test methods.
MyJUnitTests.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.stream.Stream;
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.DisplayName;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class MyJUnitTests {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
@RepeatedTest(3)
void repeatedMultiplicationTest() {
System.out.println("---Inside repeatedMultiplicationTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
@ParameterizedTest
@ValueSource(strings = { "Krishn", "Arjun", "Bheem" })
void checkUserAvailabilityTest(String userName) {
System.out.println("---Inside checkUserAvailabilityTest---");
Utility utility = new Utility();
assertTrue(utility.isUserAvailable(userName), "User will exist");
}
@TestFactory
@DisplayName("User Availability Test with @TestFactory")
Stream<DynamicTest> userAvailabilityDynamicTest() {
System.out.println("---Inside userAvailabilityDynamicTest---");
Utility utility = new Utility();
return Stream.of("Krishn", "Arjun", "Bheem")
.map(userName -> DynamicTest.dynamicTest("Test " + userName, () -> {
System.out.println(userName);
assertTrue(utility.isUserAvailable(userName), "User will exist");
}));
}
}
Output
---Inside initAll---
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
Start...[1] Krishn
---Inside checkUserAvailabilityTest---
Finished...[1] Krishn
Start...[2] Arjun
---Inside checkUserAvailabilityTest---
Finished...[2] Arjun
Start...[3] Bheem
---Inside checkUserAvailabilityTest---
Finished...[3] Bheem
Start...User Availability Test with @TestFactory
---Inside userAvailabilityDynamicTest---
Krishn
Arjun
Bheem
Finished...User Availability Test with @TestFactory
Start...repetition 1 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 1 of 3
Start...repetition 2 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 2 of 3
Start...repetition 3 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 3 of 3
---Inside tearDownAll---
@BeforeAll and @AfterAll with Interface Static Methods
We can use @BeforeAll
and @AfterAll
with interface static methods. We will create here a lifecycle logger using interface. To use our logger, we will create a class implementing the interface and then write test methods. Find the example.
LifecycleLogger.java
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.TestInfo;
public interface LifecycleLogger {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
default void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
default void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
MyMultiplicationTest.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class MyMultiplicationTest implements LifecycleLogger {
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
}
Output
---Inside initAll---
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
---Inside tearDownAll---
@BeforeAll and @AfterAll with Interface Non-Static Methods (Default Methods) using @TestInstance
We can use @BeforeAll
and @AfterAll
annotations with non-static methods (default methods) of interface using @TestInstance
annotation. @TestInstance
is a type-level annotation that is used to configure lifecycle of instances of annotated test class or test interface. @TestInstance
works with following lifecycle mode.
Lifecycle.PER_METHOD: A new test instance will be created for each test method or test factory method. PER_METHOD
mode is the default mode when @TestInstance
has not explicitly declared on test class or test interface.
Lifecycle.PER_CLASS: A new test instance will be created once per test class. The advantage of PER_CLASS
mode is that we can use non-static @BeforeAll
and @AfterAll
methods.
In our example we will create a lifecycle logger interface annotated with @TestInstance
with mode Lifecycle.PER_CLASS
and we will create non-static @BeforeAll
and @AfterAll
methods as interface default methods. Find the example.
LifecycleLoggerWithTestInstance.java
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.TestInfo;
import org.junit.jupiter.api.TestInstance;
import org.junit.jupiter.api.TestInstance.Lifecycle;
@TestInstance(Lifecycle.PER_CLASS)
public interface LifecycleLoggerWithTestInstance {
@BeforeAll
default void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
default void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
default void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
default void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
MyAdditionTest.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class MyAdditionTest implements LifecycleLoggerWithTestInstance {
@Test
@DisplayName("Add Test")
void addTest() {
System.out.println("---Inside addTest---");
Utility utility = new Utility();
assertEquals(11, utility.addNumbers(5, 6), "6 + 5 will be 11");
}
}
Output
---Inside initAll---
Start...Add Test
---Inside addTest---
Finished...Add Test
---Inside tearDownAll---
To run the example, the source code and import into IDE. To run a test class, right click on the test class -> Run’##.Test’. We will get output in console. If we are using JUnit 4 environment to run JUnit 5 examples then we need to annotate our test class with @RunWith(JUnitPlatform.class)
annotation.
Reference
JUnit 5 @BeforeEach and @AfterEach Example
This page will walk through JUnit 5 @BeforeEach
and @AfterEach
example. @BeforeEach
and @AfterEach
annotations are the analogous to @Before
and @After
annotations respectively of JUnit 4. The methods annotated with @BeforeEach
and @AfterEach
execute before and after respectively for each method annotated with @Test
, @RepeatedTest
, @ParameterizedTest
, or @TestFactory
in current class. @BeforeEach
and @AfterEach
annotated methods must not be static and must not return a value otherwise they will throw runtime exception. We can use @BeforeEach
and @AfterEach
annotations with default methods of interface but cannot be used with static methods of interface. Now find the @BeforeEach
and @AfterEach
complete example step by step.
Technologies Used
Find the technologies being used in our example.
1.Java 8
2.JUnit 5
3.Maven 3.6.3
4.Idea 2021.2.3
Maven Build File
Find the Maven build file to resolve the JUnit 5 JAR dependencies.
pom.xml
<dependencies>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-engine</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-params</artifactId>
<version>5.8.1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.platform</groupId>
<artifactId>junit-platform-launcher</artifactId>
<version>1.8.1</version>
<scope>test</scope>
</dependency>
</dependencies>
@BeforeEach and @AfterEach with @Test
@Test
annotation denotes that method is a test method. Here we will create methods annotated with @BeforeEach
and @AfterEach
and @Test
. We will observe that the @BeforeEach
annotated method will run before each @Test
annotated method and @AfterEach
annotated method will run after each @Test
annotated method. Find the example.
UsingTestAnnotationWithEach.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestInfo;
public class UsingTestAnnotationWithEach {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
@Test
@DisplayName("Add Test")
void addTest() {
System.out.println("---Inside addTest---");
Utility utility = new Utility();
assertEquals(11, utility.addNumbers(5, 6), "6 + 5 will be 11");
}
}
We should take care that @BeforeEach
and @AfterEach
annotated methods must not be static and must not return a value otherwise they will throw runtime exception. @DisplayName
is used to declare a custom display name for annotated test class or test method. TestInfo
is used to get the information about the current test.
Output
Start...Add Test
---Inside addTest---
Finished...Add Test
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
Find the sample utility class that we are using in our example to write test cases.
Utility.java
import java.util.Arrays;
import java.util.List;
public class Utility {
List<String> allUsers = Arrays.asList("Mahesh", "Ram", "Krishn", "Arjun", "Bheem");
public long multiplyNumbers(int num1, int num2) {
return num1 * num2;
}
public long addNumbers(int num1, int num2) {
return num1 + num2;
}
public boolean isUserAvailable(String userName) {
return allUsers.contains(userName);
}
}
@BeforeEach and @AfterEach with @RepeatedTest
@RepeatedTest
denotes that a method is a test template for a repeated test. Here we will create methods annotated with @BeforeEach
and @AfterEach
and @RepeatedTest
. We will observe that @BeforeEach
and @AfterEach
annotated method will execute before and after respectively for every repeated execution of @RepeatedTest
annotated method. Find the example.
UsingRepeatedTestAnnotationWithEach.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.TestInfo;
public class UsingRepeatedTestAnnotationWithEach {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@RepeatedTest(3)
void repeatedMultiplicationTest() {
System.out.println("---Inside repeatedMultiplicationTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
}
Output
Start...repetition 1 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 1 of 3
Start...repetition 2 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 2 of 3
Start...repetition 3 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 3 of 3
@BeforeEach and @AfterEach with @ParameterizedTest
@ParameterizedTest
denotes that method is parameterized test. Here we will create methods annotated with @BeforeEach
and @AfterEach
and @ParameterizedTest
. The value for parameterized test is provided by @ValueSource
annotation. The test method annotated with @ParameterizedTest
will execute for each parameter provided by @ValueSource
and for every execution of @ParameterizedTest
method, the @BeforeEach
and @AfterEach
annotated method will also execute before and after respectively. Find the example.
UsingParameterizedTestAnnotationWithEach.java
import static org.junit.jupiter.api.Assertions.assertTrue;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class UsingParameterizedTestAnnotationWithEach {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@ParameterizedTest
@ValueSource(strings = { "Krishn", "Arjun", "Bheem" })
void checkUserAvailabilityTest(String userName) {
System.out.println("---Inside checkUserAvailabilityTest---");
Utility utility = new Utility();
assertTrue(utility.isUserAvailable(userName), "User will exist");
}
}
Output
Start...[1] Krishn
---Inside checkUserAvailabilityTest---
Finished...[1] Krishn
Start...[2] Arjun
---Inside checkUserAvailabilityTest---
Finished...[2] Arjun
Start...[3] Bheem
---Inside checkUserAvailabilityTest---
Finished...[3] Bheem
@BeforeEach and @AfterEach with @TestFactory
@TestFactory
denotes that method is test factory for dynamic test. A dynamic test is a test case generated at run time. It is created using JUnit DynamicTest
API. Here we will create methods annotated with @BeforeEach
and @AfterEach
and @TestFactory
. A @TestFactory
annotated method returns Stream
, Collection
, Iterable
etc. In our example we are using @TestFactory
with Stream
. At run time the parameter for testing will be provided by Java Stream
. In the dynamic test lifecycle @BeforeEach
and @AfterEach
methods are executed for the @TestFactory
method but not for each dynamic test. The @BeforeEach
annotated method will execute before execution of @TestFactory
annotated method and @AfterEach
annotated method will execute after complete execution of @TestFactory
annotated method. Find the example.
UsingTestFactoryAnnotationWithEach.java
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.stream.Stream;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.TestInfo;
public class UsingTestFactoryAnnotationWithEach {
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@TestFactory
@DisplayName("User Availability Test with @TestFactory")
Stream<DynamicTest> userAvailabilityDynamicTest() {
System.out.println("---Inside userAvailabilityDynamicTest---");
Utility utility = new Utility();
return Stream.of("Krishn", "Arjun", "Bheem")
.map(userName -> DynamicTest.dynamicTest("Test " + userName, () -> {
System.out.println(userName);
assertTrue(utility.isUserAvailable(userName), "User will exist");
}));
}
}
Output
Start...User Availability Test with @TestFactory
---Inside userAvailabilityDynamicTest---
Krishn
Arjun
Bheem
Finished...User Availability Test with @TestFactory
@BeforeEach and @AfterEach with @Test, @RepeatedTest, @ParameterizedTest and @TestFactory
Here we will write test cases using @BeforeEach
and @AfterEach
with @Test
, @RepeatedTest
, @ParameterizedTest
and @TestFactory
altogether to check their order of execution. We will also use @BeforeAll
and @AfterAll
in test class. @BeforeAll
annotated method executes only once before all test cases and @AfterAll
annotated method executes only once after all test cases in current class. Find the example.
MyBeforeAfterJUnitTests.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.util.stream.Stream;
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.DisplayName;
import org.junit.jupiter.api.DynamicTest;
import org.junit.jupiter.api.RepeatedTest;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestFactory;
import org.junit.jupiter.api.TestInfo;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
public class MyBeforeAfterJUnitTests {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
@RepeatedTest(3)
void repeatedMultiplicationTest() {
System.out.println("---Inside repeatedMultiplicationTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
@ParameterizedTest
@ValueSource(strings = { "Krishn", "Arjun", "Bheem" })
void checkUserAvailabilityTest(String userName) {
System.out.println("---Inside checkUserAvailabilityTest---");
Utility utility = new Utility();
assertTrue(utility.isUserAvailable(userName), "User will exist");
}
@TestFactory
@DisplayName("User Availability Test with @TestFactory")
Stream<DynamicTest> userAvailabilityDynamicTest() {
System.out.println("---Inside userAvailabilityDynamicTest---");
Utility utility = new Utility();
return Stream.of("Krishn", "Arjun", "Bheem")
.map(userName -> DynamicTest.dynamicTest("Test " + userName, () -> {
System.out.println(userName);
assertTrue(utility.isUserAvailable(userName), "User will exist");
}));
}
}
Output
---Inside initAll---
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
Start...[1] Krishn
---Inside checkUserAvailabilityTest---
Finished...[1] Krishn
Start...[2] Arjun
---Inside checkUserAvailabilityTest---
Finished...[2] Arjun
Start...[3] Bheem
---Inside checkUserAvailabilityTest---
Finished...[3] Bheem
Start...User Availability Test with @TestFactory
---Inside userAvailabilityDynamicTest---
Krishn
Arjun
Bheem
Finished...User Availability Test with @TestFactory
Start...repetition 1 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 1 of 3
Start...repetition 2 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 2 of 3
Start...repetition 3 of 3
---Inside repeatedMultiplicationTest---
Finished...repetition 3 of 3
---Inside tearDownAll---
@BeforeEach and @AfterEach with Interface Default Methods
We can use @BeforeEach
and @AfterEach
annotations with default methods of interface but cannot be used with static methods of interface. Here we will create a lifecycle logger interface and then create @BeforeEach
and @AfterEach
annotated methods as default methods. To use our lifecycle logger interface we will create a test class by implementing our logger interface.
LifecycleLogger.java
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.TestInfo;
public interface LifecycleLogger {
@BeforeAll
static void initAll() {
System.out.println("---Inside initAll---");
}
@AfterAll
static void tearDownAll() {
System.out.println("---Inside tearDownAll---");
}
@BeforeEach
default void init(TestInfo testInfo) {
System.out.println("Start..." + testInfo.getDisplayName());
}
@AfterEach
default void tearDown(TestInfo testInfo) {
System.out.println("Finished..." + testInfo.getDisplayName());
}
}
MyMultiplicationTest.java
import static org.junit.jupiter.api.Assertions.assertEquals;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
public class MyMultiplicationTest implements LifecycleLogger {
@Test
@DisplayName("Multiplication Test")
void multiplyTest() {
System.out.println("---Inside multiplyTest---");
Utility utility = new Utility();
assertEquals(30, utility.multiplyNumbers(5, 6), "6 * 5 will be 30");
}
}
Output
---Inside initAll---
Start...Multiplication Test
---Inside multiplyTest---
Finished...Multiplication Test
---Inside tearDownAll---
To run the example, the source code and import into IDE. To run a test class, right click on the test class -> Run’##.Test’. We will get output in console. If we are using JUnit 4 environment to run JUnit 5 examples then we need to annotate our test class with @RunWith(JUnitPlatform.class)
annotation.