JUnit testing framework is built on annotations. JUnit 5 is a major upgrade from JUnit 4. There are different modules and we need JUnit Platform and JUnit Jupiter API to create and run the test cases for our java project.
Table of Contents
JUnit Annotations
Let’s look at the most important annotations in JUnit 5 Jupiter API. Most of them are located in the org.junit.jupiter.api
package in the junit-jupiter-api
module.
@Test
@Test annotation is used to specify that the annotated method is a test method.
@Test methods must not be private or static. @Test methods must not return a value.
@Test methods may optionally declare parameters to be resolved by ParameterResolvers.
Here is a simple example of the @Test method.
@Test
void testMethod1() {
System.out.println("test method");
}
@ParameterizedTest
JUnit @ParameterizedTest annotation is used to run a test method multiple times with different arguments. This annotation is defined in junit-jupiter-params
module. This annotation also requires us to define a source for the method arguments. Some of the annotations that can be used as arguments provider are ValueSource
, EnumSource
, MethodSource
, CsvSource
, and CsvFileSource
. Here is a simple example of using @ParameterizedTest annotation.
@ParameterizedTest
@ValueSource(strings = { "1", "2", "3" })
void test_ValueSource_String(String s) {
assertTrue(Integer.parseInt(s) < 5);
}
You can read more about them at JUnit Parameterized Tests.
@RepeatedTest
JUnit @RepeatedTest annotation is used to repeat a test specified number of times.
@RepeatedTest(5)
void test() {
System.out.println("@RepeatedTest Simple Example");
}
Above test will be executed 5 times, read more at JUnit Repeated Tests.
@TestFactory
JUnit @TestFactory annotation coupled with DynamicTest can be used to create a test factory method. JUnit @TestFactory methods must not be private or static. These methods must return a Stream, Collection, Iterable, or Iterator of DynamicNode instances. Here is a simple example of the @TestFactory method to create dynamic tests at runtime.
@TestFactory
Collection<DynamicTest> dynamicTests() {
return Arrays.asList(
dynamicTest("simple dynamic test", () -> assertTrue(true)),
dynamicTest("My Executable Class", new MyExecutable()),
dynamicTest("simple dynamic test-2", () -> assertTrue(true))
);
}
We can generate dynamic tests for a class method too, read more at JUnit 5 Dynamic Tests.
@TestInstance
We can use @TestInstance annotation to change the lifecycle behavior of a class. By default, JUnit creates a new instance of each test class before executing each test method. This behavior is called “per-method” test instance lifecycle. We can change it to “per-class” mode for faster processing of tests because a new test instance will be created once per test class.
@TestInstance(Lifecycle.PER_CLASS)
class InnerClass {
//tests
}
@DisplayName
This annotations is used to define a custom display name for test class and methods.
@DisplayName("MyTestClass")
public class DisplayNameTest {
}
@Test
@DisplayName("Example Test Method with No Business Logic")
void test() {
assertTrue(3 > 0);
}
You can read more about it at JUnit Display Name.
@Nested
JUnit Jupiter @Nested annotation is used to mark a nested class to be included in the test cases. By default, nested classes are not scanned for test methods. The nested class should be non-static. You can read more about them at JUnit Nested Tests.
@Disabled
JUnit @Disabled annotation is the easiest way to disable a test. It can be applied to a test method as well as on the Class itself.
@Test
@Disabled
void test() {
assertTrue(true);
}
@Disabled("Explicitly Disabled")
class DisabledTests {
//all tests disabled
}
JUnit Jupiter provides various annotations to enable or disable a test based on specified condition. Some of them are @DisabledOnOs
, @EnabledOnOs
, @DisabledOnJre
, @EnabledOnJre
, @DisabledIfEnvironmentVariable
, @EnabledIfEnvironmentVariable
, @DisabledIfSystemProperty
, @EnabledIfSystemProperty
, @DisabledIf
, and @EnabledIf
.
You can get complete details about these annotations at JUnit Disable Enable Tests.
JUnit Lifecycle Callback Annotations
There are four annotations that we can use to define callback methods at various stages of test cases execution.
@BeforeEach
Denotes that the annotated method should be executed before each @Test, @RepeatedTest, @ParameterizedTest, or @TestFactory method in the current class.
@AfterEach
Used to define a method to be executed after each test method in the current class. These methods gets executed for each tests in the nested classes too.
@BeforeAll
Used to define a method to be executed before all test methods in the current class. This method must be static, unless TestInstance is set to “per-class” mode.
@AfterAll
This annotation is used to define a method to be executed after all test methods in the current class. This method must be static, unless TestInstance is set to “per-class” mode.
@BeforeAll
static void setUpBeforeClass() throws Exception {
System.out.println("Set Up Before Class - @BeforeAll");
}
@AfterAll
static void tearDownAfterClass() throws Exception {
System.out.println("Tear Down After Class - @AfterAll");
}
@BeforeEach
void setUp() throws Exception {
System.out.println("Set Up @BeforeEach");
}
@AfterEach
void tearDown() throws Exception {
System.out.println("Tear Down @AfterEach");
}
JUnit lifecycle callback methods can be used to initialize or destroy resources for the test. They can also be used to reset any shared variables before test cases are executed.
Summary
JUnit testing framework is built on Java annotations. They are an integral part of JUnit framework and helps us in writing tests easily with less code.