Java after test testing

Туториал по JUnit 5 — Жизненный цикл JUnit 5 теста

Это продолжение туториала по JUnit 5. Введение опубликовано здесь.

В JUnit 5 жизненный цикл теста управляется четырьмя основными аннотациями, то есть @BeforeAll, @BeforeEach, @AfterEach и @AfterAll. Вместе с тем, каждый тестовый метод должен быть помечен аннотацией @Test из пакета org.junit.jupiter.api.

  1. Фазы жизненного цикла теста
  2. Аннотации Before и After
  3. Отключение тестов
  4. Assertions
  5. Assumptions

1. Фазы жизненного цикла теста

Обычно тестовый класс содержит несколько тестовых методов. JUnit управляет выполнением каждого метода тестирования в форме жизненного цикла.

Полный жизненный цикл тестового сценария можно разделить на три фазы с помощью аннотаций.

Фазы жизненного цикла теста

  1. Setup (настройка): на этом этапе создается тестовая инфраструктура. JUnit обеспечивает настройку уровня класса (@BeforeAll) и настройку уровня метода (@BeforeEach). Как правило, тяжелые объекты, такие как подключения к базам данных, создаются при настройке уровня класса, в то время как легкие объекты, такие как тестовые объекты, перезапускаются при настройке уровня метода.
  2. Test Execution (выполнение теста): на этом этапе происходит выполнение теста и assertion. Результат выполнения будет означать успех или неудачу теста.
  3. Cleanup (очистка): этот этап используется для очистки настройки тестовой инфраструктуры, настроенной на первом этапе. Как на этане настройки, очистка также выполняется на уровне класса (@AfterAll) и уровне метода (@AfterEach).

2. Аннотации Before и After

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

  • В JUnit по умолчанию для каждого метода тестирования создается новый экземпляр теста.
  • Аннотации @BeforeAll и @AfterAll — понятные по названию — должны вызываться только один раз за весь цикл выполнения тестов. Поэтому они должны быть объявлены static .
  • @BeforeEach и @AfterEach вызываются для каждого экземпляра теста, поэтому они не должны быть static .
  • Если есть несколько методов, помеченных одной и той же аннотацией (например, два метода с @BeforeAll ), то порядок их выполнения не определен.
public class AppTest < @BeforeAll static void setup()< System.out.println("@BeforeAll executed"); >@BeforeEach void setupThis() < System.out.println("@BeforeEach executed"); >@Test void testCalcOne() < System.out.println("======TEST ONE EXECUTED======="); Assertions.assertEquals( 4 , Calculator.add(2, 2)); >@Test void testCalcTwo() < System.out.println("======TEST TWO EXECUTED======="); Assertions.assertEquals( 6 , Calculator.add(2, 4)); >@AfterEach void tearThis() < System.out.println("@AfterEach executed"); >@AfterAll static void tear() < System.out.println("@AfterAll executed"); >>
@BeforeAll executed @BeforeEach executed ======TEST ONE EXECUTED======= @AfterEach executed @BeforeEach executed ======TEST TWO EXECUTED======= @AfterEach executed @AfterAll executed

3. Отключение тестов

Чтобы отключить тест в JUnit 5, вам нужно будет использовать аннотацию @Disabled. Это эквивалентно аннотации @Ignored JUnit 4.

Читайте также:  Python shutil copy directory

Аннотация @Disabled может быть применена к классу тестирования (отключает все методы тестирования в этом классе) или к отдельным методам тестирования.

@Disabled @Test void testCalcTwo() < System.out.println("======TEST TWO EXECUTED====== https://howtodoinjava.com/junit-5/junit-5-assertions-examples" rel="noopener noreferrer nofollow">Assertions (утверждений).

Утверждения помогают сравнить ожидаемый результат с фактическим результатом теста. Для простоты все утверждения JUnit Jupiter являются статическими методами в классе org.junit.jupiter.Assertions.

@Test public void test() < //Test will pass Assertions.assertEquals(4, Calculator.add(2, 2)); //Test will fail Assertions.assertEquals(3, Calculator.add(2, 2), "Calculator.add(2, 2) test failed"); //Test will fail SuppliermessageSupplier = ()-> "Calculator.add(2, 2) test failed"; Assertions.assertEquals(3, Calculator.add(2, 2), messageSupplier); >

Чтобы тест не прошел, просто используйте метод Assertions.fail() .

5. Assumptions

Assumptions (предположения) предоставляют static методы для поддержки выполнения условного теста на основе предположений. Неуспешное предположение приводит к прерыванию теста.

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

Класс предположений имеет три метода со многими перегруженными формами:

  1. assumeFalse(): проверяет, что данное предположение false.
  2. assumeTrue() : подтверждает данное предположение, чтобы быть true.
  3. assumingThat() : выполняет предоставленный метод Executable , но только если предоставленное предположение верно.
@Test void testOnDev() < System.setProperty("ENV", "DEV"); Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV"))); //remainder of test will proceed >@Test void testOnProd() < System.setProperty("ENV", "PROD"); Assumptions.assumeTrue("DEV".equals(System.getProperty("ENV"))); //remainder of test will be aborted >

Выше перечислены аннотации и классы для жизненного цикла JUnit теста.

Источник

JUnit 5 Test Lifecycle: Before and After Annotations

In this tutorial, we will learn how to run code before and after each test or all tests in the test class. We will also see what is the execution order when using nested tests or extensions.

This article is part of the JUnit 5 Tutorial.

Lifecycle Methods

A lifecycle method is any method that is annotated with @BeforeAll , @AfterAll , @BeforeEach or @AfterEach annotation. The lifecycle methods execute before or after executing the actual test methods.

The @BeforeAll and @AfterAll annotations denote that the annotated method should be executed before or after all test methods in the test class.

Respectively, @BeforeEach and @AfterEach mean the annotated method should be executed before or after each test method in the test class.

If you have ten test methods in the test class, @BeforeEach and @AfterEach will be executed ten times, but @BeforeAll and @AfterAll only once.

Test Instance Lifecycle

By default, JUnit creates a new instance of the test class before executing each test method. This helps us to run individual test methods in isolation and avoids unexpected side effects.

To see how this works, let’s take a look at the following example:

Notice how the methods annotated with @BeforeAll and @AfterAll are static methods. This is because when creating a new test instance per test method, there is no shared state otherwise.

The following illustration makes it easier to understand.

Executing the tests in the test class gives us the following output (actually, the output has been formatted to make it more obvious):

Looking at the output, we can see that JUnit constructs the test class once per each test method. The lifecycle methods for the entire fixture have been executed once, and the lifecycle methods for tests have been executed multiple times.

Test Instance Per Class

It is also possible to make JUnit execute all test methods on the same test instance. If we annotate the test class with @TestInstance(Lifecycle.PER_CLASS) , JUnit will create a new test instance once per test class.

Because of the shared instance, there is now no need for the methods to be static:

 Again, the following illustration helps to understand what is happening.

Consequently, the output of the test execution is now a little different:

From the results, we can see that the execution order of the lifecycle methods has not changed However, the difference is that JUnit constructs the test class only once.

The fundamental difference is that in the default lifecycle method constructing a new test class instance resets the state stored in instance variables. When the per class lifecycle method constructs the instance only once, state stored in instance variables is shared between tests.

If your test methods rely on state stored in instance variables, you may need to reset the state in @BeforeEach or @AfterEach lifecycle methods.

Try to avoid writing tests that rely on state stored in instance variables.

More Concrete Example

Now that we know how the lifecycle methods work, it’s good to explore how they can be used in practice. Usually, if we have something computationally expensive, we might want to share that with multiple tests.

Examples of this are opening a database connection, retrieving a context from a dependency injection framework, or reading a file.

In the following example, we start up a server only once per test instance:

Lifecycle methods can be applied to nested tests as well. However, by default, @BeforeAll and @AfterAll methods do not work. This is because nested tests need to be inner classes, and Java does not support static methods for inner classes.

The way to make it work is to annotate the nested class with @TestInstance(Lifecycle.PER_CLASS) :

As we can see, the lifecycle methods apply to the nested tests individually:

Additional reading:

Extension Lifecycle

When using extensions, JUnit calls extension lifecycle callbacks in addition to the lifecycle methods of the test class.

JUnit guarantees wrapping behavior for multiple registered extensions. Given extensions ExtensionOne and ExtensionTwo , it’s guaranteed the “before” callbacks of ExtensionOne execute before ExtensionTwo . Similarly, it’s guaranteed any “after” callbacks of ExtensionOne execute after ExtensionTwo .

Again, let’s take a look at an example:

Executing the example, we can see the wrapping behavior of the extensions:

Additional reading: JUnit 5 documentation has more in-depth details about the relative execution order of user code and extensions.

Summary

To execute a piece of code before and after each test, we can use the JUnit 5 @BeforeEach and @AfterEach annotations. In addition, to execute code once for all tests in the test instance, we can use the @BeforeAll and @AfterAll annotations.

Furthermore, we can change test instances to be created once per test class by annotating the test class with @TestInstance(Lifecycle.PER_CLASS) . This also enables the “before all” and “after all” lifecycle methods for nested tests.

Finally, when registering multiple extensions, JUnit 5 guarantees wrapping behavior for their lifecycle callbacks.

The example code for this guide can be found on GitHub.

Clean Code Corner

Short, simple, and actionable tips on developing quality software.

Join for free. No spam. Unsubscribe at any time.

Arho Huttunen
Software Crafter

A software professional seeking for simple solutions to complex problems.

© 2015-2023 Arho Huttunen. All rights reserved.

Источник

Оцените статью