Статьи

Жизненный цикл JUnit 5 Extension Model

Финальная версия JUnit5 не за горами (в настоящее время это M4), и я начал с ней играть, как писать расширения.

В JUnit5 вместо того, чтобы иметь дело с Runners , Rules , ClassRules и т. Д., У вас есть один API расширений для реализации ваших собственных расширений.

JUnit5 предоставляет несколько интерфейсов для подключения в своем жизненном цикле. Например, вы можете подключиться к постобработке тестового экземпляра, чтобы вызвать пользовательские методы инициализации в экземпляре теста, или к параметру Resolution для динамического разрешения параметров метода теста во время выполнения. И, конечно, типичные, такие как перехват перед выполнением всех тестов, перед выполнением теста, после выполнения теста и т. Д., Полный список можно найти по адресу http://junit.org/junit5/docs/. текущий / пользователь руководство / # удлинители-жизненный цикл обратных вызовов

Но в какой точке процесса выполняется каждый из них? Чтобы проверить это, я только что создал расширение, которое реализует все интерфейсы, и каждый метод выводит, кто это.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
public class LoggerExtension implements TestInstancePostProcessor, ParameterResolver, BeforeAllCallback,
    BeforeEachCallback, BeforeTestExecutionCallback, AfterEachCallback, AfterTestExecutionCallback, AfterAllCallback,
    TestExecutionExceptionHandler {
    @Override
    public void postProcessTestInstance(Object testInstance, ExtensionContext context) throws Exception {
        System.out.println("Test Instance Post-processing called");
    }
 
    @Override
    public boolean supports(ParameterContext parameterContext, ExtensionContext extensionContext)
        throws ParameterResolutionException {
        System.out.println("Parameter Resolver Supports called");
        return parameterContext.getParameter().getType().equals(String.class);
    }
 
    @Override
    public Object resolve(ParameterContext parameterContext, ExtensionContext extensionContext)
        throws ParameterResolutionException {
        System.out.println("Resolver called");
        return "Hello World";
    }
 
    @Override
    public void beforeAll(ContainerExtensionContext context) throws Exception {
        System.out.println("Before All called " + context.getTestClass().get());
    }
 
    @Override
    public void beforeEach(TestExtensionContext context) throws Exception {
        System.out.println("Before Each called");
    }
 
    @Override
    public void beforeTestExecution(TestExtensionContext context) throws Exception {
        System.out.println("Before Test Execution called");
    }
 
    @Override
    public void afterEach(TestExtensionContext context) throws Exception {
        System.out.println("After Each called");
    }
 
    @Override
    public void afterTestExecution(TestExtensionContext context) throws Exception {
        System.out.println("After Test Executon called");
    }
 
    @Override
    public void afterAll(ContainerExtensionContext context) throws Exception {
        System.out.println("After All called");
    }
 
    @Override
    public void handleTestExecutionException(TestExtensionContext context, Throwable throwable) throws Throwable {
        System.out.println("Test Execution Exception called");
        throw throwable;
    }
}

Затем я создал набор тестов JUnit5, содержащий два теста:

1
2
3
4
5
6
7
8
9
@ExtendWith(LoggerExtension.class)
public class AnotherLoggerExtensionTest {
 
    @Test
    public void test4() {
        System.out.println("Test 4");
    }
 
}
01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
@ExtendWith(LoggerExtension.class)
public class LoggerExtensionTest {
 
    @Test
    public void test1() {
        System.out.println("Test 1");
    }
 
    @Test
    public void test2(String msg) {
        System.out.println("Test 2 " + msg);
    }
 
    @Test
    public void test3() {
        System.out.println("Test 3");
        throw new IllegalArgumentException("");
    }
 
}
1
2
3
4
@RunWith(JUnitPlatform.class)
@SelectClasses({LoggerExtensionTest.class, AnotherLoggerExtensionTest.class})
public class LoggerExtensionTestSuite {
}

Итак, после выполнения этого пакета, что это будет за выход? Давай увидим это. Обратите внимание, что для удобства чтения я добавил несколько выносок на вывод терминала.

01
02
03
04
05
06
07
08
09
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
Before All called class AnotherLoggerExtensionTest
Test Instance Post-processing called
Before Each called
Before Test Execution called
Test 4
After Test Execution called
After Each called
After All called
 
// <1>
 
Before All called class LoggerExtensionTest
Test Instance Post-processing called
Before Each called
Before Test Execution called
Test 1
After Test Execution called
After Each called
 
// <2>
 
Test Instance Post-processing called
Before Each called
Before Test Execution called
Parameter Resolver Supports called
Resolver called
Test 2 Hello World
After Test Execution called
After Each called
 
// <3>
 
Test Instance Post-processing called
Before Each called
Before Test Execution called
Test 3
Test Execution Exception called
After Test Execution called
After Each called
 
// <4>
 
After All called

<1> Первый тест, который он запускает, — AnotherLoggerExtensionTest . В этом случае существует только один простой тест, поэтому жизненным циклом расширения является BeforeAll , Instance-Post-Processing теста , Before Each , Before Execution Test , затем выполняется сам тест, а затем все обратные вызовы After .

<2> Затем выполняется LoggerExtensionTest . Первый тест не является параметризованным тестом, поэтому события, связанные с разрешением параметров , не вызываются. Перед выполнением тестового метода вызывается постобработка тестового экземпляра , и после этого генерируются все события перед. Наконец тест выполняется со всеми последующими событиями.

<3> Второй тест содержит разрешение параметра. Преобразователи параметров запускаются после событий « До» и перед выполнением самого теста.

<4> Последний тест вызывает исключение. Исключение при выполнении теста вызывается после выполнения теста, но до событий After .

Последнее, на что следует обратить внимание, это то, что события BeforeAll и AfterAll выполняются для каждого класса тестирования, а не для набора.

В этом примере используется версия JUnit : org.junit.jupiter: junit-jupiter-api: 5.0.0-M4

Ссылка: Жизненный цикл JUnit 5 Extension Model от нашего партнера JCG Алекса Сото в блоге One Jar To Rule All .