Junit: разделение интеграционного теста и модульных тестов

126

Я унаследовал множество тестов Junit, но эти тесты (помимо большинства неработающих) представляют собой смесь фактических модульных тестов и интеграционных тестов (требующих внешних систем, баз данных и т. Д.).

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

Возможны следующие варианты ..

  1. Разбейте их в отдельные каталоги.

  2. Перейдите к Junit4 (из v3) и аннотируйте классы, чтобы разделить их.

  3. Используйте соглашение об именах файлов, чтобы определить класс, например AdapterATest и AdapterAIntergrationTest.

3 имеет проблему, заключающуюся в том, что Eclipse имеет возможность «Запускать все тесты в выбранном проекте / пакете или папке». Так что было бы очень сложно просто запустить интеграционные тесты.

2: есть риск, что разработчики начнут писать интеграционные тесты в классах модульных тестов, и это станет беспорядочным.

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

Итак, вот мой вопрос: как разделить интеграционные тесты и правильные модульные тесты?

Джефф Портер
источник
Я просто хотел бы поблагодарить вас всех за ваш вклад, я знаю, что это субъективный вопрос, и на него нет одного правильного ответа. Но вы помогли мне понять, что нет других вариантов, кроме тех, которые я перечислил. Я думаю, что на данный момент я собираюсь пойти со структурой каталогов и перейти к JUnit4, хотя пока не буду использовать аннотации для их разделения.
Джефф Портер,

Ответы:

10

В настоящее время я использую отдельные каталоги из-за организационной политики (и наследия Junit 3), но я сам собираюсь перейти на аннотации, теперь я использую Junit 4.

Я бы не стал особо беспокоиться о том, что разработчики помещают интеграционные тесты в ваши классы модульного тестирования - при необходимости добавьте правило в стандарты кодирования.

Мне интересно знать, какие еще могут быть решения, кроме аннотаций или физического разделения классов.

Стивен Маккензи
источник
145

Вы можете легко разделить их с помощью категорий JUnit и Maven.

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

Определить интерфейс маркера

Первым шагом в группировке теста по категориям является создание интерфейса маркера.

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

public interface IntegrationTest {}

Отметьте свои тестовые классы

Добавьте аннотацию категории в начало вашего тестового класса. Он берет имя вашего нового интерфейса.

import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class ExampleIntegrationTest{
  @Test
  public void longRunningServiceTest() throws Exception {
  }
}

Настроить модульные тесты Maven

Прелесть этого решения в том, что в части модульного тестирования ничего не меняется.

Мы просто добавляем некоторую конфигурацию в плагин maven surefire, чтобы он игнорировал любые интеграционные тесты.

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <includes>
      <include>**/*.class</include>
    </includes>
    <excludedGroups>com.test.annotation.type.IntegrationTest</excludedGroups>
  </configuration>
</plugin>

Когда вы выполняете mvn clean test, запускаются только немаркированные модульные тесты.

Настроить тесты интеграции Maven

И снова конфигурация для этого очень проста.

Чтобы запустить только интеграционные тесты, используйте это:

<plugin>
  <groupId>org.apache.maven.plugins</groupId>
  <artifactId>maven-surefire-plugin</artifactId>
  <version>2.11</version>
  <dependencies>
   <dependency>
     <groupId>org.apache.maven.surefire</groupId>
     <artifactId>surefire-junit47</artifactId>
     <version>2.12</version>
   </dependency>
  </dependencies>
  <configuration>
    <groups>com.test.annotation.type.IntegrationTest</groups>
  </configuration>
</plugin>

Если вы заключите это в профиль с идентификатором IT, вы сможете запускать только быстрые тесты, используя mvn clean install. Чтобы запустить только интеграционные / медленные тесты, используйте mvn clean install -P IT.

Но чаще всего вам нужно запускать быстрые тесты по умолчанию и все тесты с -P IT. Если это так, то вам нужно использовать трюк:

<profiles>
    <profile>
        <id>IT</id>
        <build>
            <plugins>
                <plugin>
                    <groupId>org.apache.maven.plugins</groupId>
                    <artifactId>maven-surefire-plugin</artifactId>
                    <configuration>
                        <excludedGroups>java.io.Serializable</excludedGroups> <!-- An empty element doesn't overwrite, so I'm using an interface here which no one will ever use -->
                    </configuration>
                </plugin>
            </plugins>
        </build>
    </profile>
</profiles>

Как видите, я исключаю тесты, помеченные как java.io.Serializable. Это необходимо, потому что профиль унаследует конфигурацию по умолчанию плагина Surefire, поэтому, даже если вы скажете <excludedGroups/>или <excludedGroups></excludedGroups>, значение com.test.annotation.type.IntegrationTestбудет использоваться.

Вы также не можете использовать, noneпоскольку это должен быть интерфейс в пути к классам (Maven проверит это).

Ноты:

  • Зависимость от surefire-junit47необходима только тогда, когда Maven не переключается на бегун JUnit 4 автоматически. Использование элемента groupsили excludedGroupsдолжно вызвать срабатывание переключателя. Смотрите здесь .
  • Большая часть приведенного выше кода была взята из документации для плагина Maven Failsafe. См. Раздел «Использование категорий JUnit» на этой странице .
  • Во время своих тестов я обнаружил, что это работает даже при использовании @RunWith()аннотаций для запуска наборов или тестов на основе Spring.
Джон Доби
источник
18
Я думаю, что в вашем последнем фрагменте pom.xml есть ошибка. вы вставили тот же фрагмент, что и для этапа «тестирования». он по-прежнему исключает интеграционные тесты, а также не привязан к какой-либо фазе maven.
Alex
1
Действительно, последний фрагмент pom - это ошибка копирования и вставки. Он должен показать maven-failsafe-plugin.
Пауло Мерсон
2
Так каким же тогда должен быть второй xml? : O
Лив
Вам не нужно использовать этот трюк (последняя магия с Serializable), если вы используете профиль Maven по умолчанию
user831217
Это действительно должен быть принятый ответ, потому что на самом деле это решение вопроса, а не философские дебаты о том, где разместить различные тесты.
Bwvolleyball
40

Мы используем Maven Surefire Plugin для запуска модульных тестов и Maven Failsafe Plugin для запуска интеграционных тестов. Модульные тесты следуют **/Test*.java **/*Test.java **/*TestCase.javaсоглашениям об именах, интеграционные тесты - **/IT*.java **/*IT.java **/*ITCase.java. Так что на самом деле это ваш вариант номер три.

В паре проектов мы используем TestNG и определяем разные тестовые группы для интеграционных / модульных тестов, но это, вероятно, вам не подходит.

lexicore
источник
1
+1 за комбинацию maven + surefire + failsafe + junit. Я не понимал, что отказоустойчивый запускает "IT *" автоматически. Сладкий.
PapaFreud
13

Я бы перешел на Junit4 только за то, что он есть :)

Вы можете разделить их на разные наборы тестов. Я не знаю, как они организованы в Junit3, но в Junit4 должно быть легко просто создать наборы тестов и поместить все реальные модульные тесты в один из них, а затем использовать второй набор для интеграционных тестов.

Теперь определите конфигурацию запуска для обоих наборов в eclipse, и вы легко сможете запустить один набор. Эти комплекты также могут быть запущены из автоматизированного процесса, позволяющего запускать модульные тесты каждый раз при изменении источника и, возможно, интеграционные тесты (если они действительно большие) только один раз в день или один раз в час.

Януш
источник
9

Использование аннотации Spring IfProfileValue позволяет достичь этого без плагина maven или требуемой конфигурации.

Аннотируйте классы или методы интеграционных тестов с помощью IfProfileValue

import org.springframework.test.annotation.IfProfileValue;

@IfProfileValue(name="test-groups", value="integration")
public class ExampleIntegrationTest{
    @Test
    public void longRunningServiceTest() throws Exception {
    }
} 

Для запуска только с использованием модульных тестов:

mvn clean test

Для запуска с использованием интеграционного теста и модульных тестов:

mvn clean test -Dtest-groups=integration

Кроме того, «Запустить весь тест» в среде IDE будет запускаться только модульный тест. Добавьте -Dtest-groups=integrationк ВМ аргументы для запуска как интеграционных, так и модульных тестов.

Мит Мехта
источник
Этот подход хорош и прост, но я обнаружил, что по умолчанию я хотел бы запустить все тесты (включая интеграционные). Это невозможно при таком подходе, не так ли?
csalazar
6

Нет одного правильного ответа. Как вы объяснили, есть несколько эффективных способов сделать это. Я сделал и схему именования файлов, и разбил вещи по разным каталогам.

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

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

NDP
источник