JUnit 5 Tutorials

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

Annotation Type Disabled

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 User Guide

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 User Guide

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.

Reference

JUnit 5 User Guide

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值