Use of Commonly Used Annotations in JUnit5
- 2021-10-16 01:46:42
- OfStack
Meta-annotation and combined annotation
Summary
References:
Annotation (Annotations) is the signature technology of JUnit, so this article will study its 20 annotations, meta-annotations and composite annotations.
20 notes
These annotations are defined in the package org. junit. jupiter. api as follows:
@ Test test method, which can be run directly.
@ ParameterizedTest parameterized tests, such as:
@ParameterizedTest
@ValueSource(strings = { "racecar", "radar", "able was I ere I saw elba" })
void palindromes(String candidate) {
assertTrue(StringUtils.isPalindrome(candidate));
}
@ RepeatedTest Repeat tests, such as:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
@ TestFactory test factory, which specializes in generating test methods, such as:
import org.junit.jupiter.api.DynamicTest;
@TestFactory
Collection<DynamicTest> dynamicTestsFromCollection() {
return Arrays.asList(
dynamicTest("1st dynamic test", () -> assertTrue(isPalindrome("madam"))),
dynamicTest("2nd dynamic test", () -> assertEquals(4, calculator.multiply(2, 2)))
);
}
@ TestTemplate test templates, such as:
final List<String> fruits = Arrays.asList("apple", "banana", "lemon");
@TestTemplate
@ExtendWith(MyTestTemplateInvocationContextProvider.class)
void testTemplate(String fruit) {
assertTrue(fruits.contains(fruit));
}
public class MyTestTemplateInvocationContextProvider
implements TestTemplateInvocationContextProvider {
@Override
public boolean supportsTestTemplate(ExtensionContext context) {
return true;
}
@Override
public Stream<TestTemplateInvocationContext> provideTestTemplateInvocationContexts(
ExtensionContext context) {
return Stream.of(invocationContext("apple"), invocationContext("banana"));
}
}
@ TestTemplate must register an TestTemplateInvocationContextProvider, which is used similarly to @ Test.
@ TestMethodOrder specifies the test sequence, such as:
import org.junit.jupiter.api.MethodOrderer.OrderAnnotation;
import org.junit.jupiter.api.Order;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.TestMethodOrder;
@TestMethodOrder(OrderAnnotation.class)
class OrderedTestsDemo {
@Test
@Order(1)
void nullValues() {
// perform assertions against null values
}
@Test
@Order(2)
void emptyValues() {
// perform assertions against empty values
}
@Test
@Order(3)
void validValues() {
// perform assertions against valid values
}
}
Whether @ TestInstance generates multiple test instances? By default, JUnit generates one instance per test method. Using this annotation, each class can only generate one instance, such as:
@TestInstance(Lifecycle.PER_CLASS)
class TestMethodDemo {
@Test
void test1() {
}
@Test
void test2() {
}
@Test
void test3() {
}
}
@ DisplayName custom test name will be reflected in the test report, such as:
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Test;
@DisplayName("A special test case")
class DisplayNameDemo {
@Test
@DisplayName("Custom test name containing spaces")
void testWithDisplayNameContainingSpaces() {
}
@Test
@DisplayName(" °-°) ")
void testWithDisplayNameContainingSpecialCharacters() {
}
@Test
@DisplayName("😱")
void testWithDisplayNameContainingEmoji() {
}
}
@ DisplayNameGeneration test name system 1 processing, such as:
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.DisplayNameGeneration;
import org.junit.jupiter.api.DisplayNameGenerator;
import org.junit.jupiter.api.IndicativeSentencesGeneration;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.params.ParameterizedTest;
import org.junit.jupiter.params.provider.ValueSource;
class DisplayNameGeneratorDemo {
@Nested
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
class A_year_is_not_supported {
@Test
void if_it_is_zero() {
}
@DisplayName("A negative value for year is not supported by the leap year computation.")
@ParameterizedTest(name = "For example, year {0} is not supported.")
@ValueSource(ints = { -1, -4 })
void if_it_is_negative(int year) {
}
}
@Nested
@IndicativeSentencesGeneration(separator = " -> ", generator = DisplayNameGenerator.ReplaceUnderscores.class)
class A_year_is_a_leap_year {
@Test
void if_it_is_divisible_by_4_but_not_by_100() {
}
@ParameterizedTest(name = "Year {0} is a leap year.")
@ValueSource(ints = { 2016, 2020, 2048 })
void if_it_is_one_of_the_following_years(int year) {
}
}
}
@ BeforeEach is executed before each @ Test, @ RepeatedTest, @ ParameterizedTest, or @ TestFactory.
@ AfterEach is executed after each @ Test, @ RepeatedTest, @ ParameterizedTest, or @ TestFactory.
@ BeforeAll is executed before all @ Test, @ RepeatedTest, @ ParameterizedTest, and @ TestFactory.
@ AfterAll is executed after all @ Test, @ RepeatedTest, @ ParameterizedTest, and @ TestFactory.
@ Nested nested test, 1 class sets 1 class, refer to the above one for examples.
@ Tag labeling is equivalent to grouping, such as:
import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;
@Tag("fast")
@Tag("model")
class TaggingDemo {
@Test
@Tag("taxes")
void testingTaxCalculation() {
}
}
@ Disabled disables testing, such as:
import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.Test;
@Disabled("Disabled until bug #99 has been fixed")
class DisabledClassDemo {
@Test
void testWillBeSkipped() {
}
}
@Timeout For test, test factory, test template, or lifecycle method If you time out, you will be considered a failure, such as:
class TimeoutDemo {
@BeforeEach
@Timeout(5)
void setUp() {
// fails if execution time exceeds 5 seconds
}
@Test
@Timeout(value = 100, unit = TimeUnit.MILLISECONDS)
void failsIfExecutionTimeExceeds100Milliseconds() {
// fails if execution time exceeds 100 milliseconds
}
}
@ ExtendWith registration extensions, such as:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
0
JUnit5 provides a standard extension mechanism to allow developers to enhance the functionality of JUnit5. JUnit5 provides a number of standard extension interfaces that third parties can directly implement to provide custom behavior.
@ RegisterExtension registers extensions through fields, such as:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
1
@ TempDir temporary directory, such as:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
2
Meta-annotation and combined annotation
JUnit Jupiter supports meta-annotations and enables custom annotations, such as custom @ Fast annotations:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import org.junit.jupiter.api.Tag;
@Target({ ElementType.TYPE, ElementType.METHOD })
@Retention(RetentionPolicy.RUNTIME)
@Tag("fast")
public @interface Fast {
}
Use:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
4
This @ Fast annotation is also a combination annotation, which can even be combined with @ Test one step further:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
5
Just use @ FastTest:
@RepeatedTest(10)
void repeatedTest() {
// ...
}
6
Summary
This paper introduces and demonstrates 20 main annotations of JUnit. JUnit Jupiter supports meta-annotation, which can be customized or combined with multiple annotations.
References:
https://junit.org/junit5/docs/current/user-guide/#writing-tests-annotations
Overview of https://vitzhou. gitbooks. io/junit5/content/junit/extension _ model. html #