Главная страница
Навигация по странице:

  • 4. Заключение

  • 4.1. TestInstancePostProcessor Extension

  • 4.2. Условное выполнение теста

  • 4.3. Обратные вызовы жизненного цикла

  • 4.4. Разрешение параметра

  • Basic Java Tools for Building & Testing Apps


    Скачать 4.76 Mb.
    НазваниеBasic Java Tools for Building & Testing Apps
    АнкорJUNIt
    Дата14.11.2022
    Размер4.76 Mb.
    Формат файлаpdf
    Имя файла5_2_0_Maven_JUnit_Tutorial.pdf
    ТипРеферат
    #787190
    страница12 из 16
    1   ...   8   9   10   11   12   13   14   15   16
    Наиболее важным является то, что мы больше не можем
    использовать аннотацию @ Test для указания ожиданий.
    Параметр expected в JUnit 4:
    @Test
    (expected = Exception.class) public void shouldRaiseAnException
    () throws
    Exception {
    //...
    }
    Теперь мы можем использовать метод assertThrows : public void shouldRaiseAnException
    () throws
    Exception {
    Assertions.assertThrows(Exception.class, () -> {
    //...
    });
    }
    Атрибут timeout в JUnit 4:

    @Test
    (timeout =
    1
    ) public void shouldFailBecauseTimeout
    () throws
    InterruptedException {
    Thread.sleep(
    10
    );
    }
    Теперь метод assertTimeout в JUnit 5:
    @Test public void shouldFailBecauseTimeout
    () throws
    InterruptedException {
    Assertions.assertTimeout(Duration.ofMillis(
    1
    ), () -> Thread.sleep(
    10
    ));
    }
    Другие аннотации, которые были изменены в JUnit 5:

    @ Before аннотация переименована в @ BeforeEach

    @ After аннотация переименована в @ AfterEach

    @ BeforeClass аннотация переименована в @ BeforeAll

    @ AfterClass аннотация переименована в @ AfterAll

    @ Ignore аннотация переименована в @ Disabled
    3.2. Утверждения
    Теперь мы можем написать сообщения с утверждениями в лямбда-выражениях в JUnit 5, что позволяет при отложенной оценке пропускать сложное построение сообщения до тех пор, пока это не понадобится:
    @Test public void shouldFailBecauseTheNumbersAreNotEqual__lazyEvaluation
    () {
    Assertions.assertTrue(
    2
    ==
    3
    ,
    () ->
    "Numbers "
    +
    2
    +
    " and "
    +
    3
    +
    " are not equal!"
    );
    }
    Мы также можем сгруппировать утверждения в JUnit 5:
    @Test public void shouldAssertAllTheGroup
    () {
    List list = Arrays.asList(
    1
    ,
    2
    ,
    4
    );
    Assertions.assertAll(
    "List is not incremental"
    ,
    () -> Assertions.assertEquals(list.get(
    0
    ).intValue(),
    1
    ),
    () -> Assertions.assertEquals(list.get(
    1
    ).intValue(),
    2
    ),
    () -> Assertions.assertEquals(list.get(
    2
    ).intValue(),
    3
    ));
    }
    3.3. Предположения
    Новый класс Assumptions теперь находится в org.junit.jupiter.api.Assumptions . JUnit 5 полностью поддерживает существующие методы предположений в JUnit 4, а также добавляет набор новых методов, позволяющих запускать некоторые утверждения только в определенных сценариях:
    @Test public void whenEnvironmentIsWeb__thenUrlsShouldStartWithHttp
    () { assumingThat(
    "WEB"
    .equals(System.getenv(
    "ENV"
    )),
    () -> { assertTrue(
    "http"
    .startsWith(address));
    });
    }
    3.4. Пометка и фильтрация
    В JUnit 4 мы могли группировать тесты, используя аннотацию @ Category .
    В JUnit 5 аннотация @ Category заменяется аннотацией @ Tag :
    @Tag
    (
    "annotations"
    )
    @Tag
    (
    "junit5"
    )
    @RunWith
    (JUnitPlatform.class) public class
    AnnotationTestExampleTest
    {
    /** ...** /}

    Мы можем включить/исключить определенные теги, используя maven-surefire-plugin :
    <
    build
    >
    <
    plugins
    >
    <
    plugin
    >
    <
    artifactId
    >maven-surefire-pluginartifactId
    >
    <
    configuration
    >
    <
    properties
    >
    <
    includeTags
    >junit5includeTags
    >
    properties
    >
    configuration
    >
    plugin
    >
    plugins
    >
    build
    >
    3.5. Новые аннотации для запуска тестов
    @ RunWith использовался для интеграции тестового контекста с другими платформами или для изменения общего потока выполнения в тестовых примерах в JUnit 4.
    С помощью JUnit 5 теперь мы можем использовать аннотацию @ ExtendWith для обеспечения аналогичной функциональности.
    В качестве примера, чтобы использовать функции Spring в JUnit 4:
    @RunWith
    (SpringJUnit4ClassRunner.class)
    @ContextConfiguration
    (
    {
    "/app-config.xml"
    ,
    "/test-data-access-config.xml"
    }) public class
    SpringExtensionTest
    {
    /** ...** /}
    Теперь в JUnit 5 это простое расширение:
    @ExtendWith
    (SpringExtension.class)
    @ContextConfiguration
    (
    {
    "/app-config.xml"
    ,
    "/test-data-access-config.xml"
    }) public class
    SpringExtensionTest
    {
    /** ...** /}
    3.6. Новые аннотации правил испытаний
    В JUnit 4 аннотации @ Rule и @ ClassRule использовались для добавления специальных функций в тесты.
    В JUnit 5. мы можем воспроизвести ту же логику, используя аннотацию @ ExtendWith .
    Например, скажем, у нас есть пользовательское правило в JUnit 4 для записи трассировок журнала до и после теста: public class
    TraceUnitTestRule implements
    TestRule
    {
    @Override public
    Statement apply
    (Statement base, Description description) { return new
    Statement() {
    @Override public void evaluate
    () throws
    Throwable {
    //Before and after an evaluation tracing here
    }
    };
    }
    }
    И мы реализуем это в тестовом наборе:
    @Rule public
    TraceUnitTestRule traceRuleTests = new
    TraceUnitTestRule();
    В JUnit 5 мы можем написать то же самое гораздо более интуитивно понятным способом:
    public class
    TraceUnitExtension implements
    AfterEachCallback
    ,
    BeforeEachCallback
    {
    @Override public void beforeEach
    (TestExtensionContext context) throws
    Exception {
    //...
    }
    @Override public void afterEach
    (TestExtensionContext context) throws
    Exception {
    //...
    }
    }
    Используя интерфейсы AfterEachCallback и BeforeEachCallback в JUnit 5, доступные в пакете org.junit.jupiter.api.extension, мы легко реализуем это правило в комплекте тестов:
    @RunWith
    (JUnitPlatform.class)
    @ExtendWith
    (TraceUnitExtension.class) public class
    RuleExampleTest
    {
    @Test public void whenTracingTests
    () {
    /** ...** / }
    }
    3.7. Юнит 5 Винтаж
    JUnit Vintage помогает в миграции тестов JUnit, выполняя тесты JUnit 3 или JUnit 4 в контексте JUnit 5.
    Мы можем использовать его, импортировав JUnit Vintage Engine:
    <
    dependency
    >
    <
    groupId
    >org.junit.vintagegroupId
    >
    <
    artifactId
    >junit-vintage-engineartifactId
    >
    <
    version
    >${junit5.vintage.version}version
    >
    <
    scope
    >testscope
    >
    dependency
    >
    4. Заключение
    Как мы видели в этой статье, JUnit 5 - это модульная и современная версия платформы JUnit 4. Мы ввели основные различия между этими двумя версиями и намекнули, как перейти с одной на другую
    Руководство по расширению JUnit 5

    Testing
    JUnit 5

    FacebookTumblrPinterestPocketEvernoteTwitterLineEmailRedditDiggVKРесурс
    1. Обзор
    В этой статье мы рассмотрим модель расширения в библиотеке тестирования JUnit 5. Как следует из названия, цель
    расширений Junit 5 состоит в том, чтобы расширить поведение тестовых классов или методов , и они могут быть повторно использованы для нескольких тестов.
    До 5 июня версия библиотеки JUnit 4 использовала два типа компонентов для расширения теста: исполнители тестов и правила. Для сравнения, JUnit 5 упрощает механизм расширения, вводя единую концепцию: API Extension .
    2. Модель расширения JUnit 5
    Расширения JUnit 5 относятся к определенному событию при выполнении теста, называемому точкой расширения.
    Когда достигается определенная фаза жизненного цикла, механизм JUnit вызывает зарегистрированные расширения.
    Можно использовать пять основных типов точек расширения:

    постобработка тестового экземпляра

    условное выполнение теста

    обратные вызовы жизненного цикла

    разрешение параметра

    Обработка исключений
    Мы рассмотрим каждый из них более подробно в следующих разделах.
    3. Зависимости Maven
    Во-первых, давайте добавим зависимости проекта, которые нам понадобятся для наших примеров.
    Нам понадобится основная библиотека JUnit 5: junit-jupiter-engine :
    <
    dependency
    >
    <
    groupId
    >org.junit.jupitergroupId
    >
    <
    artifactId
    >junit-jupiter-engineartifactId
    >
    <
    version
    >5.1.0version
    >
    <
    scope
    >testscope
    >
    dependency
    >
    Также давайте добавим две вспомогательные библиотеки для использования в наших примерах:
    <
    dependency
    >
    <
    groupId
    >org.apache.logging.log4jgroupId
    >
    <
    artifactId
    >log4j-coreartifactId
    >
    <
    version
    >2.8.2version
    >
    dependency
    >
    <
    dependency
    >
    <
    groupId
    >com.h2databasegroupId
    >
    <
    artifactId
    >h2artifactId
    >
    <
    version
    >1.4.196version
    >
    dependency
    >
    Последние версии junit-jupiter-engine
    , https://search.maven.org/classic/#search
    % 7Cga% 7C1% 7Ca% 3A% 22h2% 22%
    20AND% 20g% 3A% 22com.h2database% 22[h2]и https://search.maven.org/classic/#search%7Cga%7C1%7Ca%3A
    % 22log4j- core% 22% 20AND% 20g% 3A% 22org.apache.logging.log4j% 22[log4j-core]можно загрузить из Maven Central.
    4. Создание расширений JUnit 5
    Чтобы создать расширение JUnit 5, нам нужно определить класс, который реализует один или несколько интерфейсов, соответствующих точкам расширения JUnit 5. Все эти интерфейсы расширяют основной интерфейс Extension , который является только интерфейсом маркера.
    4.1. TestInstancePostProcessor Extension
    Расширение этого типа выполняется после того, как был создан экземпляр теста. Интерфейс для реализации
    - TestInstancePostProcessor , у которого есть метод postProcessTestInstance () для переопределения.

    Типичным вариантом использования этого расширения является внедрение зависимостей в экземпляр. Например, давайте создадим расширение, которое создает экземпляр объекта logger , а затем вызывает метод setLogger () в тестовом экземпляре: public class
    LoggingExtension implements
    TestInstancePostProcessor
    {
    @Override public void postProcessTestInstance
    (Object testInstance,
    ExtensionContext context) throws
    Exception {
    Logger logger = LogManager.getLogger(testInstance.getClass()); testInstance.getClass()
    .getMethod(
    "setLogger"
    , Logger.class)
    .invoke(testInstance, logger);
    }
    }
    Как видно выше, метод postProcessTestInstance () обеспечивает доступ к экземпляру теста и вызывает метод setLogger
    () класса теста, используя механизм отражения.
    4.2. Условное выполнение теста
    JUnit 5 предоставляет тип расширения, который может контролировать, следует ли запускать тест. Это определяется реализацией интерфейса ExecutionCondition .
    Давайте создадим класс EnvironmentExtension , который реализует этот интерфейс и переопределяет метод evaluateExecutionCondition () .
    Метод проверяет, равняется ли свойство, представляющее имя текущей среды, «qa» , и отключает тест в этом случае: public class
    EnvironmentExtension implements
    ExecutionCondition
    {
    @Override public
    ConditionEvaluationResult evaluateExecutionCondition
    (
    ExtensionContext context) {
    Properties props = new
    Properties(); props.load(EnvironmentExtension.class
    .getResourceAsStream(
    "application.properties"
    ));
    String env = props.getProperty(
    "env"
    ); if
    (
    "qa"
    .equalsIgnoreCase(env)) { return
    ConditionEvaluationResult
    .disabled(
    "Test disabled on QA environment"
    );
    } return
    ConditionEvaluationResult.enabled(
    "Test enabled on QA environment"
    );
    }
    }
    В результате тесты, которые регистрируют это расширение, не будут выполняться в среде «qa» .

    Если мы не хотим, чтобы условие было проверено, мы можем деактивировать его, установив ключ конфигурации junit.conditions.deactivate ** в шаблон, соответствующий условию.
    Это может быть достигнуто путем запуска JVM со свойством -Djunit.conditions.deactivate =
    или путем добавления параметра конфигурации в LauncherDiscoveryRequest : public class
    TestLauncher
    { public static void main
    (String[]args) {
    LauncherDiscoveryRequest request
    = LauncherDiscoveryRequestBuilder.request()
    .selectors(selectClass(
    "com.baeldung.EmployeesTest"
    ))
    .configurationParameter(
    "junit.conditions.deactivate"
    ,
    "com.baeldung.extensions.** "
    )
    .build();

    TestPlan plan = LauncherFactory.create().discover(request);
    Launcher launcher = LauncherFactory.create();
    SummaryGeneratingListener summaryGeneratingListener
    = new
    SummaryGeneratingListener(); launcher.execute( request, new
    TestExecutionListener[]{ summaryGeneratingListener });
    System.out.println(summaryGeneratingListener.getSummary());
    }
    }
    4.3. Обратные вызовы жизненного цикла
    Этот набор расширений связан с событиями в жизненном цикле теста и может быть определен путем реализации следующих интерфейсов:

    BeforeAllCallback и AfterAllCallback - выполняется до и после все методы испытаний выполнены ** BeforeEachCallBack и AfterEachCallback - выполняется до и после каждого метода испытаний ** BeforeTestExecutionCallback и AfterTestExecutionCallback - выполняется непосредственно перед и сразу после метода испытаний
    Если тест также определяет методы его жизненного цикла, порядок выполнения такой:
    , BeforeAllCallback
    , BeforeAll
    , BeforeEach Callback
    , BeforeEach
    , BeforeTestExecutionCallback
    , Тестовое задание
    , AfterTestExecutionCallback
    , AfterEach
    , AfterEachCallback
    , В конце концов
    , AfterAllCallback
    В нашем примере давайте определим класс, который реализует некоторые из этих интерфейсов и управляет поведением теста, который обращается к базе данных с помощью JDBC.
    Сначала давайте создадим простую сущность Employee : public class
    Employee
    { private long id; private
    String firstName;
    //constructors, getters, setters
    }
    Нам также понадобится служебный класс, который создает Connection на основе файла .properties :
    public class
    JdbcConnectionUtil
    { private static
    Connection con; public static
    Connection getConnection
    () throws
    IOException, ClassNotFoundException, SQLException{ if
    (con == null
    ) {
    //create connection return con;
    } return con;
    }
    }
    Наконец, давайте добавим простой DAO на основе JDBC, который манипулирует записями Employee : public class
    EmployeeJdbcDao
    { private
    Connection con; public
    EmployeeJdbcDao
    (Connection con) { this
    .con = con;
    } public void createTable
    () throws
    SQLException {
    //create employees table
    } public void add
    (Employee emp) throws
    SQLException {
    //add employee record
    } public
    List findAll
    () throws
    SQLException {
    //query all employee records
    }
    }

    Давайте создадим наше расширение, которое реализует некоторые интерфейсы жизненного цикла: ** public class
    EmployeeDatabaseSetupExtension implements
    BeforeAllCallback
    ,
    AfterAllCallback
    ,
    BeforeEachCallback
    ,
    AfterEachCallback
    {
    //...
    }
    Каждый из этих интерфейсов содержит метод, который мы должны переопределить.
    Для интерфейса BeforeAllCallback мы переопределим метод beforeAll () и добавим логику для создания нашей таблицы employees перед выполнением любого тестового метода: private
    EmployeeJdbcDao employeeDao = new
    EmployeeJdbcDao();
    @Override public void beforeAll
    (ExtensionContext context) throws
    SQLException { employeeDao.createTable();
    }
    Далее мы будем использовать BeforeEachCallback и AfterEachCallback , чтобы обернуть каждый тестовый метод в транзакции. Цель этого - откатить любые изменения в базе данных, выполненные в методе test, чтобы следующий тест выполнялся на чистой базе данных.
    В методе beforeEach () мы создадим точку сохранения, которая будет использоваться для отката состояния базы данных: private
    Connection con = JdbcConnectionUtil.getConnection(); private
    Savepoint savepoint;
    @Override public void beforeEach
    (ExtensionContext context) throws
    SQLException { con.setAutoCommit(
    false
    ); savepoint = con.setSavepoint(
    "before"
    );
    }

    Затем в методе afterEach () мы откатим изменения в базе данных, сделанные во время выполнения тестового метода:
    @Override public void afterEach
    (ExtensionContext context) throws
    SQLException { con.rollback(savepoint);
    }
    Чтобы закрыть соединение, мы будем использовать метод afterAll () , который выполняется после завершения всех тестов:
    @Override public void afterAll
    (ExtensionContext context) throws
    SQLException { if
    (con != null
    ) { con.close();
    }
    }
    4.4. Разрешение параметра
    Если конструктор или метод теста получает параметр, он должен быть разрешен во время выполнения ParameterResolver .
    Давайте определим наш собственный ParameterResolver , который разрешает параметры типа EmployeeJdbcDao : public class
    EmployeeDaoParameterResolver implements
    ParameterResolver
    {
    @Override public boolean supportsParameter
    (ParameterContext parameterContext,
    ExtensionContext extensionContext) throws
    ParameterResolutionException { return parameterContext.getParameter().getType()
    .equals(EmployeeJdbcDao.class);
    }
    @Override public
    Object resolveParameter
    (ParameterContext parameterContext,
    ExtensionContext extensionContext) throws
    ParameterResolutionException { return new
    EmployeeJdbcDao();
    }
    }
    Наш распознаватель реализует интерфейс ParameterResolver и переопределяет методы supportsParameter
    () и resolveParameter () . Первый из них проверяет тип параметра, а второй определяет логику для получения экземпляра параметра.
    1   ...   8   9   10   11   12   13   14   15   16


    написать администратору сайта