Статьи

Интеграционное тестирование с Gradle

Модульное тестирование работает автоматически с использованием Gradle, но если вы хотите получить отдельный набор интеграционных тестов, вам нужно выполнить небольшое упражнение. На самом деле они вообще не должны быть интеграционными тестами. В этом руководстве показано, как настроить Gradle на использование любых видов тестов и запуск их независимо от других. Я буду использовать язык Scala здесь, но то же самое работает для любого языка JVM.

Цель

Мы собираемся определить новую задачу Gradle с именем itest, которая будет запускать только тесты, реализованные в определенной папке «src / itest / scala». Стандартный встроенный тест задачи будет работать без каких-либо изменений, запустив только тесты в каталоге «src / test / scala».

Стандартный Java / Scala Project

Мы начнем со стандартного проекта Gradle Java или Scala. Язык программирования здесь не имеет значения. Обычно структура каталогов выглядит так:

1
2
3
4
5
6
7
<project root>
  + src
    + main
      + scala
    + test
      + scala
  - build.gradle

Основной исходный код (который тестируется) находится в «src / main / scala», а все модульные тесты находятся в «src / test / scala».

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

Мы уже знаем, где находятся наши юнит-тесты. Хорошая привычка — называть их по классу, который они тестируют, после чего следует суффикс «Test» или «Spec». Например, если тестируемый класс называется «Miracle», то для него должны быть выполнены модульные тесты класса «MiracleSpec» (или MiracleTest, если хотите). Это просто соглашение, не более того.

Мы будем использовать тот же принцип для интеграционных тестов, но поместим их в каталог «src / itest / scala» и будем использовать суффикс «ITest» или «ISpec» . Это также соглашение, но оно позволяет нам запускать их отдельно от модульных тестов.

Почему специальный каталог, а также специальный суффикс имени?

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

Например, если вы упаковываете все приложение в один большой толстый JAR-файл и хотите запускать только интеграционные тесты. Как бы Вы это сделали? Некоторые тестеры поддерживают фильтрацию только по классу / имени файла. Для этого вы должны использовать регулярное выражение «* ISpec».

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

Пример структуры проекта

Представьте себе проект Scala с одним классом реализации под названием Fujara (потрясающий словацкий музыкальный инструмент). Его модульные тесты находятся в классе FujaraSpec, а интеграционные тесты — в FujaraISpec. Часто нам нужны некоторые данные для интеграционных тестов (itest-data.xml) или конфигурации журналирования (logback-test.xml), отличной от основной конфигурации журналирования приложения.

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
<project root>
  + src
    + itest
      + resources
        + com
          + buransky
            - itest-data.xml
        logback-test.xml
      + scala
        + com
          + buransky
            - FujaraISpec.scala
    + main
      + resources
        - logback.xml
      + scala
        + com
          + buransky
            - Fujara.scala
    + test
      + scala
        + com
          + buransky
            - FujaraSpec.scala
  - build.gradle

Build.gradle

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

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
configurations {
  itestCompile.extendsFrom testCompile
  itestRuntime.extendsFrom testRuntime
}
 
sourceSets {
  itest {
    compileClasspath += main.output + test.output
    runtimeClasspath += main.output + test.output
 
    // You can add other directories to the classpath like this:
    //runtimeClasspath += files('src/itest/resources/com/buransky')
 
    // Use "java" if you don't use Scala as a programming language
    scala.srcDir file('src/itest/scala')
  }
 
  // This is just to trick IntelliJ IDEA to add integration test
  // resources to classpath when running integration tests from
  // the IDE. It's is not a good solution but I don't know about
  // a better one.
  test {
    resources.srcDir file('src/itest/resources')
  }
}
 
task itest(type: Test) {
  testClassesDir = sourceSets.itest.output.classesDir
  classpath = sourceSets.itest.runtimeClasspath
 
  // This is not needed, but I like to see which tests have run
  testLogging {
    events "passed", "skipped", "failed"
  }
}

Запустите интеграционные тесты

Теперь мы сможем запустить интеграционный тест, просто выполнив задачу «gradle itest» . В нашем примере он должен запускать только FujaraISpec. Чтобы запустить модульные тесты в FujaraSpec, выполните «gradle test».

Определите другие типы тестов

Если вы хотите использовать тот же принцип для функциональных тестов, тестов производительности, приемочных тестов или любых других тестов, просто скопируйте и вставьте приведенный выше код и замените «itest» на «ftest», «ptest», «atest», «xtest», …