Home JUnit 5 - Annotations
Post
Cancel

JUnit 5 - Annotations

JUnit 5 Annotations

JUnit is a popular open-source unit testing framework for Java. It provides a convenient way to test your Java code and make sure it works as expected. JUnit 5 is the latest version of JUnit, which brings many improvements and new features, including new annotations. In this blog post, we will explore JUnit 5 annotations and how to use them to write effective tests.

@Test

@Test is the most commonly used JUnit 5 annotation. It indicates that the annotated method is a test method. JUnit will execute this method when running the test suite. For example:

1
2
3
4
5
@Test
void testAddition() {
int result = 1 + 2;
assertEquals(3, result);
}

@DisplayName

@DisplayName is used to specify a custom name for the test. By default, the name of the test method is used as the test name. You can use @DisplayName to give a more meaningful name to the test, which can help you understand the purpose of the test. For example:

1
2
3
4
5
6
@Test
@DisplayName("Test addition of two numbers")
void testAddition() {
int result = 1 + 2;
assertEquals(3, result);
}

@BeforeEach and @AfterEach

@BeforeEach and @AfterEach are used to specify methods that should be executed before and after each test method, respectively. @BeforeEach can be used to set up the test environment, while @AfterEach can be used to clean up the environment after the test. For example:

1
2
3
4
5
6
7
8
9
@BeforeEach
void setUp() {
// set up the test environment
}

@AfterEach
void tearDown() {
// clean up the environment after the test
}

@BeforeAll and @AfterAll

@BeforeAll and @AfterAll are used to specify methods that should be executed before and after all test methods in the test class, respectively. These methods should be static. @BeforeAll can be used to set up the test environment, while @AfterAll can be used to clean up the environment after all tests have been executed. For example:

1
2
3
4
5
6
7
8
9
@BeforeAll
static void setUp() {
// set up the test environment
}

@AfterAll
static void tearDown() {
// clean up the environment after all tests have been executed
}

@Disabled

@Disabled is used to disable a test method. This can be useful when you need to temporarily disable a test without deleting it. For example:

1
2
3
4
5
@Test
@Disabled("Not implemented yet")
void testMultiplication() {
// this test is not implemented yet
}

@ParameterizedTest

@ParameterizedTest is used to specify a test method that should be executed with different sets of parameters. This can help you write more concise and effective tests. For example:

1
2
3
4
5
6
@ParameterizedTest
@ValueSource(ints = {1, 2, 3})
void testAddition(int number) {
int result = 1 + number;
assertTrue(result > 1);
}

@RepeatedTest

@RepeatedTest is used to specify a test method that should be executed multiple times. This can be useful when you need to test the same functionality with different inputs. For example:

1
2
3
4
5
@RepeatedTest(5)
void testAddition() {
int result = 1 + 2;
assertEquals(3, result);
}

@TestFactory

The @TestFactory annotation is used to generate dynamic tests at runtime. It is useful when you need to create a set of tests based on a set of inputs. The @TestFactory method must return a collection of dynamic tests. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
@TestFactory
Stream<DynamicTest> testAddition() {
List<Pair<Integer, Integer>> input = Arrays.asList(
Pair.of(1, 2),
Pair.of(3, 4),
Pair.of(5, 6)
);
return input.stream()
.map(pair -> DynamicTest.dynamicTest(
"Addition of " + pair.getLeft() + " and " + pair.getRight(),
() -> assertEquals(pair.getLeft() + pair.getRight(), 3)
));
}

In this example, we are creating a set of dynamic tests for different pairs of numbers. Each dynamic test is generated using the DynamicTest.dynamicTest() method, which takes the test name and the test body as arguments.

@TestTemplate

The @TestTemplate annotation is used to define a template for parameterized tests. It is useful when you need to test a set of inputs using the same test logic. The @TestTemplate method must be annotated with the @DisplayName annotation to give the parameterized test a name. Here is an example:

1
2
3
4
5
6
7
@TestTemplate
@DisplayName("Test addition with {0} and {1}")
@CsvSource({"1,2", "3,4", "5,6"})
void testAddition(int a, int b) {
int result = a + b;
assertEquals(3, result);
}

In this example, we are using the @CsvSource annotation to provide the input data for the parameterized test. The testAddition() method takes two arguments that are mapped to the input data in the @CsvSource annotation.

@TestClassOrder

The @TestClassOrder annotation is used to define the order in which test classes are executed. It can be useful when you have dependencies between test classes. The @TestClassOrder annotation must be used in combination with the @Order annotation to specify the execution order. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
@TestClassOrder(OrderAnnotation.class)
@Order(2)
public class ClassATest {
@Test
void testA() {
// test logic
}
}

@TestClassOrder(OrderAnnotation.class)
@Order(1)
public class ClassBTest {
@Test
void testB() {
// test logic
}
}

In this example, we are using the @TestClassOrder and @Order annotations to specify the order in which ClassATest and ClassBTest should be executed. ClassBTest has a lower order value than ClassATest, so it will be executed before ClassATest.

@TestMethodOrder

The @TestMethodOrder annotation is used to define the order in which test methods are executed. It can be useful when you have dependencies between test methods. The @TestMethodOrder annotation must be used in combination with the @Order annotation to specify the execution order. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@TestMethodOrder(OrderAnnotation.class)
public class TestOrder {
    @Test
    @Order(2)
    void testA() {
        // test logic
    }

    @Test
    @Order(1)
    void testB() {
        // test logic
    }

    @Test
    @Order(3)
    void testC() {
        // test logic
    }
}

In this example, we are using the @TestMethodOrder and @Order annotations to specify the order in which test methods should be executed. testB() has a lower order value than testA(), so it will be executed before testA(). Similarly, testC() has a higher order value than testA() and testB(), so it will be executed last.

@TestInstance

The @TestInstance annotation is used to control how JUnit 5 creates and manages test instances. It can be useful when you need to reuse test instance state between test methods. The @TestInstance annotation has two modes: PER_CLASS and PER_METHOD. PER_CLASS is the default mode and creates a single test instance for the entire test class. PER_METHOD creates a new test instance for each test method. Here is an example:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@TestInstance(TestInstance.Lifecycle.PER_CLASS)
public class TestInstanceExample {
    private int count = 0;

    @Test
    void testA() {
        count++;
        assertEquals(1, count);
    }

    @Test
    void testB() {
        count++;
        assertEquals(1, count);
    }
}

In this example, we are using the @TestInstance annotation with the PER_CLASS mode to create a single test instance for the entire TestInstanceExample class. We are also using a private variable count to track the state of the test instance between test methods.

@Timeout

The @Timeout annotation is used to specify a maximum duration that a test method is allowed to run. If the test method takes longer than the specified duration, it will be terminated and marked as a failure. Here is an example:

1
2
3
4
5
6
@Test
@Timeout(5)
void testMethod() throws InterruptedException {
Thread.sleep(6000);
// test logic
}

In this example, we are using the @Timeout annotation to set a maximum duration of 5 seconds for the testMethod(). The Thread.sleep(6000) call is intentionally included to exceed the maximum duration and trigger a failure.

@ExtendWith

The @ExtendWith annotation is used to register custom extensions that provide additional behavior to your tests. An extension can be used to add custom test lifecycle callbacks, custom parameter resolvers, or custom test execution condition checks. Here is an example:

1
2
3
4
@ExtendWith(MyCustomExtension.class)
public class MyTest {
// test methods
}

In this example, we are using the @ExtendWith annotation to register the MyCustomExtension extension with the MyTest class. MyCustomExtension can provide additional behavior to the test methods, such as logging or performance profiling.

@RegisterExtension

The @RegisterExtension annotation is used to register test extensions with the test class at the field level. This annotation is similar to @ExtendWith, but it allows for more fine-grained control over the lifecycle of the extension. Here is an example:

1
2
3
4
5
6
public class MyTest {
@RegisterExtension
MyCustomExtension myCustomExtension = new MyCustomExtension();

    // test methods
}

In this example, we are using the @RegisterExtension annotation to register the MyCustomExtension extension as a field in the MyTest class. This allows us to define the extension’s scope and lifecycle more precisely.

@Tag

The @Tag annotation is used to tag test methods or classes with metadata. This can be useful for organizing and filtering tests based on their characteristics. Here is an example:

1
2
3
4
5
6
7
@Tag("fast")
public class MyTest {
@Test
void testMethod() {
// test logic
}
}

In this example, we are using the @Tag annotation to tag the MyTest class as “fast”. We can then use this tag to filter tests based on their execution time or other characteristics.

Conclusion

In conclusion, JUnit 5 annotations are a powerful way to write effective and concise unit tests. By using these annotations, you can make your tests more readable, maintainable, and efficient. These annotations are just some of the

This post is licensed under CC BY 4.0 by the author.