Рубрики
Без рубрики

Миграция с Junit 4 на Junit 5

Миграция с Junit 4 на Junit 5. Помеченный java, junit, junit 5, junit4.

Во время работы над моим текущим проектом у меня появилось некоторое время для перехода с JUnit 4 на JUnit 5 . Поскольку JUnit 5 был выпущен в сентябре 2017 года, сейчас самое подходящее время взглянуть на него.

Мое приложение представляет собой проект java 8 maven, разделенный на 7 модулей maven, и каждый модуль имеет собственные интеграционные и модульные тесты. Однако один из этих модулей посвящен тестам. Он содержит все необходимые для тестирования зависимости и вводится как тест области видимости в другие модули. Наши тестовые зависимости являются наиболее распространенными в Java-проекте. Мы используем JUnit 4, AssertJ , Мокито , DBUnit и Весенний тест .

Наконец, у нас также есть специальный проект для выполнения сквозных тестов на основе Selenium , Флюентлениум и Дано . К сожалению, Given не полностью поддерживает JUnit 5. В настоящее время он находится в экспериментальном состоянии , поэтому я еще не начал эту миграцию.

Зависимости

Давайте начнем с добавления новых зависимостей JUnit:


   org.junit.jupiter
   junit-jupiter-engine
   ${junit.version}


   org.junit.vintage
   junit-vintage-engine
   ${junit.version}


   org.junit.platform
   junit-platform-launcher
   ${junit.platform.version}


   org.junit.platform
   junit-platform-runner
   ${junit.platform.version}


Важно обратить внимание на импорт junit-vintage-engine . Он предоставляет возможность без труда запускать тесты JUnit 4 и JUnit 5 одновременно.

Модульные тесты

Следующим шагом будет замена всего импорта старых аннотаций JUnit на самые новые.

import org.junit.Test

становиться

import org.junit.jupiter.api.Test;

Вот отображение каждой аннотации:

org.junit. До org.junit.jupiter.api. Перед Каждым
org.junit. После org.junit.jupiter.api. После
org.junit. Перед занятием org.junit.jupiter.api. Перед всеми
org.junit. Послеклассный org.junit.jupiter.api. В конце концов
org.junit. Игнорировать org.junit.jupiter.api. Нетрудоспособный

Поскольку мы используем AssertJ для всех наших утверждений, мне не нужно было переносить утверждения JUnit4.

Правила

Одним из самых больших изменений является удаление концепции rules , которая была заменена моделью расширения . Целью расширения является расширение поведения тестовых классов или методов, и оно заменяет JUnit runner и Junit Rules.

Одно правило, которое мы все использовали, – это ExpectedException и он может быть легко заменен JUnit assertThrows :

   @Test
    void exceptionTesting() {
        Throwable exception = assertThrows(IllegalArgumentException.class, () -> {
            throw new IllegalArgumentException("a message");
        });
        assertEquals("a message", exception.getMessage());
    }

Другим хорошо известным правилом для миграции является Временная папка . К сожалению, JUnit 5 пока не предоставляет замену. В Github есть открытый issue .

Обзор

См. Обсуждение по адресу https://github.com/junit-team/junit5-samples/issues/4 .

Связанные с этим Вопросы

  • #219

Результаты

  • [X] Представить официальное лицо Временная папка расширение для JUnit Jupiter аналогично поддержке правил в JUnit 4.

Итак, что мы можем сделать, чтобы это сработало?

Прежде всего, в JUnit 4 можно поддерживать тесты с использованием этих правил благодаря junit-vintage-engine .

Другим решением является продолжение использования JUnit 4 Временная папка правьте , добавляя зависимость junit-jupiter-поддержка миграции .


    org.junit.jupiter
    junit-jupiter-migrationsupport
    ${junit.version}


Этот модуль позволяет запускать тесты JUnit 5 с правилами. Например:

@EnableRuleMigrationSupport
public class JUnit4TemporaryFolderTest {

    @Rule
    public TemporaryFolder temporaryFolder = new TemporaryFolder();

    @Test
    public void test() throws IOException {
        temporaryFolder.newFile("new_file");
    }
}

Однако эта функция поддерживает только:

  • правила, расширяющие org.junit.rules. Внешний Ресурс
  • правила, расширяющие org.junit.rules. Верификатор
  • правило Ожидаемое исключение и в настоящее время он помечен как экспериментальный , так что используйте его на свой страх и риск.

Наконец, одно из решений – создать свой собственный Расширение временной папки основано на реализации Junit 4.

public class TemporaryFolderExtension implements BeforeEachCallback, AfterEachCallback {

   private final File parentFolder;
   private File folder;

   public TemporaryFolderExtension() {
       this(null);
   }

   public TemporaryFolderExtension(File parentFolder) {
       this.parentFolder = parentFolder;
   }

   @Override
   public void afterEach(ExtensionContext extensionContext) {
       if (folder != null) {
           recursiveDelete(folder);
       }
   }

   @Override
   public void beforeEach(ExtensionContext extensionContext) throws IOException {
       folder = File.createTempFile("junit", "", parentFolder);
       folder.delete();
       folder.mkdir();
   }

   public File newFile(String fileName) throws IOException {
       File file = new File(getRoot(), fileName);
       if (!file.createNewFile()) {
           throw new IOException("a file with the name \'" + fileName + "\' already exists in the test folder");
       }
       return file;
   }

   public File newFolder(String folderName) {
       File file = getRoot();
       file = new File(file, folderName);
       file.mkdir();
       return file;
   }

   private void recursiveDelete(File file) {
       File[] files = file.listFiles();
       if (files != null) {
           for (File each : files) {
               recursiveDelete(each);
           }
       }
       file.delete();
   }

   public File getRoot() {
       if (folder == null) {
           throw new IllegalStateException("the temporary folder has not yet been created");
       }
       return folder;
   }

}

Эта реализация не полностью поддерживает все функции расширения, такие как Разрешение параметров но, по крайней мере, это позволяет нам полностью перенести наши тесты на JUnit 5. Кроме того, можно вводить расширения как правило, используя @RegisterExtension

@RegisterExtension
public TemporaryFolderExtension temporaryFolder = new TemporaryFolderExtension();

Эта аннотация позволяет нам создать расширение с параметрами и получить доступ к нему во время выполнения теста.

Пользовательские Правила

В моем случае у меня было только одно пользовательское правило для переноса. Его цель – создать SMTP-сервер в памяти для подтверждения отправки электронных писем.

public class SMTPServerRule extends ExternalResource {

   private GreenMail smtpServer;
   private String hostname;
   private int port;

   public SMTPServerRule() {
       this(25);
   }

   public SMTPServerRule(int port) {
       this("localhost", port);
   }

   public SMTPServerRule(String hostname, int port) {
       this.hostname = hostname;
       this.port = port;
   }


   @Override
   protected void before() throws Throwable {
       super.before();

       smtpServer = new GreenMail(new ServerSetup(port, hostname, "smtp"));
       smtpServer.start();
   }

   public List getMessages() {
       return Lists.newArrayList(smtpServer.getReceivedMessages()).stream()
           .parallel()
           .map(mimeMessage -> ExpectedMail.transformMimeMessage(mimeMessage)).collect(Collectors.toList());
   }

   @Override
   protected void after() {
       super.after();
       smtpServer.stop();
   }
}

Чтобы заставить его работать как расширение JUnit, ему нужно только реализовать Перед каждым обратным вызовом и |/После каждого обратного вызова интерфейсы вместо наследования от/| Внешний ресурс . Основная реализация остается прежней.

public class SMTPServerExtension implements BeforeEachCallback, AfterEachCallback {

   private GreenMail smtpServer;
   private String hostname;
   private int port;

   public SMTPServerExtension() {
       this(25);
   }

   public SMTPServerExtension(int port) {
       this("localhost", port);
   }

   public SMTPServerExtension(String hostname, int port) {
       this.hostname = hostname;
       this.port = port;
   }

   public List getMessages() {
       return Lists.newArrayList(smtpServer.getReceivedMessages()).stream()
           .parallel()
           .map(mimeMessage -> ExpectedMail.transformMimeMessage(mimeMessage)).collect(Collectors.toList());
   }


   @Override
   public void afterEach(ExtensionContext extensionContext) throws Exception {
       smtpServer.stop();
   }

   @Override
   public void beforeEach(ExtensionContext extensionContext) throws Exception {
       smtpServer = new GreenMail(new ServerSetup(port, hostname, "smtp"));
       smtpServer.start();
   }

Интеграционные тесты

Интеграционные тесты Удлинитель пружины входит в состав пружины 5.

@RunWith(SpringJUnit4ClassRunner.class)

становиться

@ExtendWith(SpringExtension.class)

Тесты Mockito

Давайте продолжим с тестами, использующими Mockito. Как мы уже делали с интеграционными тестами Spring, мы должны зарегистрировать расширение:

@RunWith(MockitoJUnitRunner.class)

становиться

@ExtendWith(MockitoExtension.class)

На самом деле, класс Расширение Mockito еще не предоставлено Mockito и это будет введено с Mockito 3. Одно из решений такое же, как Расширение временной папки … это делается для того, чтобы сохранить наши тесты в JUnit 4. Тем не менее, также возможно создать свое собственное расширение, и поэтому команда Junit предоставляет одну реализацию Mockito Extension в своих примерах. Я решил импортировать его в свой проект, чтобы завершить миграцию.

Удалить JUnit 4

Затем, чтобы убедиться, что все мои тесты выполняются под JUnit 5, я проверил, есть ли какая-либо зависимость от JUnit4, выполнив:

mvn dependency:tree

И поэтому мне пришлось исключить некоторые из них:

        
            org.springframework.boot
            spring-boot-starter-test
            
                
                    junit
                    junit
                
            
        

        
            org.dbunit
            dbunit
            ${dbunit.version}
            
                
                    junit
                    junit
                
            
        

Знаток

И последнее, но не менее важное: мне нужно было обновить плагин maven surefire, чтобы он работал с JUnit 5.


        
          org.apache.maven.plugins
          maven-surefire-plugin
          ${maven-surefire-plugin.version}
            
                
                    org.junit.platform
                    junit-platform-surefire-provider
                    1.1.1
                
                
                    org.junit.jupiter
                    junit-jupiter-engine
                    ${junit.version}
                
            
        

Будьте осторожны с версией вашего плагина maven surefire, так как 2.20 имеет утечку памяти . Документация JUnit предлагает версию 2.21 .

Вывод

Эта миграция была действительно простой, но даже в этом случае JUnit 5 полностью отличается от JUnit 4. В конце концов, я смог удалить импорт junit-vintage-engine , так как у меня больше нет теста Junit 4. Я сожалею только о том факте, что мне пришлось создать свое собственное расширение временной папки и расширение Mockito. Наконец, можно получить дополнительную помощь в вашей миграции, обратившись к Junit5-samples .

Большое спасибо Sony th , Микаэлю и Houssem за их время и корректуру.

Оригинал: “https://dev.to/vga/migration-from-junit-4-to-junit-5-19d6”