Как добавить новый источник в Gradle?

Я хочу добавить интеграционные тесты в мою сборку Gradle (версия 1.0). Они должны запускаться отдельно от моих обычных тестов, потому что они требуют развертывания веб-приложения на localhost (они тестируют это веб-приложение). Тесты должны быть в состоянии использовать классы, определенные в моем основном исходном наборе. Как мне это сделать?

11 ответов

Решение

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

Это простой скрипт сборки Gradle, у которого есть набор исходного кода intTest в дополнение к основному и тестовому исходным наборам:

apply plugin: "java"

sourceSets {
    // Note that just declaring this sourceset creates two configurations.
    intTest {
        java {
            compileClasspath += main.output
            runtimeClasspath += main.output
        }
    }
}

configurations {
    intTestCompile.extendsFrom testCompile
    intTestRuntime.extendsFrom testRuntime
}

task intTest(type:Test){
    description = "Run integration tests (located in src/intTest/...)."
    testClassesDir = project.sourceSets.intTest.output.classesDir
    classpath = project.sourceSets.intTest.runtimeClasspath
}

Вот как я добился этого без использования configurations{ },

apply plugin: 'java'

sourceCompatibility = JavaVersion.VERSION_1_6

sourceSets {
    integrationTest {
        java {
            srcDir 'src/integrationtest/java'
        }
        resources {
            srcDir 'src/integrationtest/resources'
        }
        compileClasspath += sourceSets.main.runtimeClasspath
    }
}

task integrationTest(type: Test) {
    description = "Runs Integration Tests"
    testClassesDir = sourceSets.integrationTest.output.classesDir
    classpath += sourceSets.integrationTest.runtimeClasspath
}

Протестировано с использованием: Gradle 1.4 и Gradle 1.6

Чтобы суммировать оба старых ответа (получить лучший и минимальный жизнеспособность обоих миров):

Сначала несколько теплых слов:

  1. Во-первых, нам нужно определить sourceSet:

    sourceSets {
        integrationTest
    }
    
  2. Далее мы расширяем sourceSet от test для этого мы используем test.runtimeClasspath (который включает в себя все зависимости от test А ТАКЖЕ test сам) как путь к классу для производного sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    
    • примечание) каким-то образом это объявление / продлить для sourceSets.integrationTest.runtimeClasspath необходимо, но не имеет значения, так как runtimeClasspath всегда расширяется output + runtimeSourceSet не понимаю
  3. мы определяем отдельную задачу для запуска интеграционных тестов:

    task integrationTest(type: Test) {
    }
    
  4. Настройте integrationTest тестовые классы и использование classpath. Значения по умолчанию от java плагин использовать testsourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
    
  5. (необязательно) автоматический запуск после теста

    интеграция.проверяет по тесту
    

  6. (необязательно) добавить зависимость от check (так всегда работает, когда build или же check выполнены)

    tasks.check.dependsOn(tasks.integrationTest)
    
  7. (необязательно) добавить Java, ресурсы к sourceSet поддерживать автоматическое обнаружение и создавать эти "частичные" в вашей IDE. т.е. IntelliJ IDEA автоматически создаст sourceSet каталоги java и ресурсы для каждого набора, если он не существует:

    sourceSets {
         integrationTest {
             java
             resources
         }
    }
    

ТЛ; др

apply plugin: 'java'

// apply the runtimeClasspath from "test" sourceSet to the new one
// to include any needed assets: test, main, test-dependencies and main-dependencies
sourceSets {
    integrationTest {
        // not necessary but nice for IDEa's
        java
        resources

        compileClasspath += sourceSets.test.runtimeClasspath
        // somehow this redeclaration is needed, but should be irrelevant
        // since runtimeClasspath always expands compileClasspath
        runtimeClasspath += sourceSets.test.runtimeClasspath
    }
}

// define custom test task for running integration tests
task integrationTest(type: Test) {
    testClassesDir = sourceSets.integrationTest.output.classesDir
    classpath = sourceSets.integrationTest.runtimeClasspath
}
tasks.integrationTest.dependsOn(tasks.test)

ссылаясь на:

К сожалению, пример кода на https://github.com/gradle/gradle/blob/master/subprojects/docs/src/samples/java/customizedLayout/build.gradle или …/gradle/…/withIntegrationTests/build.gradle, похоже, не справляется с этим или имеет другой / более сложный / для меня нет более ясного решения в любом случае!

Плагин Nebula-Facet устраняет шаблон:

apply plugin: 'nebula.facet'
facets {
    integrationTest {
        parentSourceSet = 'test'
    }
}

Специально для интеграционных тестов, даже это сделано для вас, просто примените:

apply plugin: 'nebula.integtest'

Ссылки на портал Gradle для каждого из них:

  1. nebula.facet
  2. nebula.integtest

Если вы используете

Чтобы IntelliJ распознал пользовательский набор источников в качестве корневых источников тестов:

plugin {
    idea
}

idea {
    module {
        testSourceDirs = testSourceDirs + sourceSets["intTest"].allJava.srcDirs
        testResourceDirs = testResourceDirs + sourceSets["intTest"].resources.srcDirs
    }
}

Вот что работает для меня с Gradle 4.0.

sourceSets {
  integrationTest {
    compileClasspath += sourceSets.test.compileClasspath
    runtimeClasspath += sourceSets.test.runtimeClasspath
  }
}

task integrationTest(type: Test) {
  description = "Runs the integration tests."
  group = 'verification'
  testClassesDirs = sourceSets.integrationTest.output.classesDirs
  classpath = sourceSets.integrationTest.runtimeClasspath
}

Начиная с версии 4.0, Gradle теперь использует отдельные каталоги классов для каждого языка в исходном наборе. Так что если ваш скрипт сборки использует sourceSets.integrationTest.output.classesDirвы увидите следующее предупреждение об устаревании.

Gradle теперь использует отдельные выходные каталоги для каждого языка JVM, но эта сборка предполагает наличие одного каталога для всех классов из исходного набора. Это поведение устарело и планируется удалить в Gradle 5.0

Чтобы избавиться от этого предупреждения, просто переключитесь на sourceSets.integrationTest.output.classesDirs вместо. Для получения дополнительной информации см. Примечания к выпуску Gradle 4.0.

Я понимаю, что в 2012 году, когда был задан этот вопрос, документация была не очень хорошей, но для тех, кто читает это в 2020+: теперь в документации есть целый раздел о том, как добавить исходный набор для интеграционных тестов. Вы действительно должны прочитать это вместо того, чтобы копировать/вставлять фрагменты кода здесь и биться головой о стену, пытаясь понять, почему ответ от 2012-2016 не совсем работает.

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

Вот решение для Kotlin (build.gradle.kts):

      sourceSets {
    create("uiTest") {
        // Adds files from the main source set to the compilation and runtime classpaths of this new source set
        // sourceSets.main.output is a collection of all the directories containing compiled main classes and resources
        compileClasspath += sourceSets.main.get().output
        runtimeClasspath += sourceSets.main.get().output
    }
}

// Makes the uiTestImplementation configuration extend from testImplementaion,
// which means that all the declared dependencies of the test code (and transitively the main as well)
// also become dependencies of this new source set
val uiTestImplementation by configurations.getting {
    extendsFrom(configurations.testImplementation.get())
}
val uiTestRuntimeOnly by configurations.getting {
    extendsFrom(configurations.testRuntimeOnly.get())
}

Бонус:

      val uiTest = task<Test>("uiTest") {
    description = "Runs UI tests."
    group = "verification"

    testClassesDirs = sourceSets["uiTest"].output.classesDirs
    classpath = sourceSets["uiTest"].runtimeClasspath

    testLogging {
        events(TestLogEvent.PASSED)
    }
}

tasks.check { dependsOn(uiTest) }

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

      sourceSets {
zxc50{
    xjcSchema {
        srcDir 'src/main/schema/target'
        includes = ['zxc50.xsd']
        xjcTargetPackage = "zxc50"
    }
}

Вы также можете настроить свои тесты для работы с jUnit:

      task integrationTest(type: Test) {
   ...
   useJunitPlatform()
}

Я новичок в Gradle, использую Gradle 6.0.1 JUnit 4.12. Вот что я придумал для решения этой проблемы.

apply plugin: 'java'
repositories { jcenter() }

dependencies {
    testImplementation 'junit:junit:4.12'
}

sourceSets {
  main {
    java {
       srcDirs = ['src']
    }
  }
  test {
    java {
      srcDirs = ['tests']
    }
  }
}

Обратите внимание, что основной источник и тестовый источник упоминаются отдельно, один под main и один под test.

В testImplementation пункт под dependencies используется только для компиляции исходного кода в test. Если ваш основной код действительно зависит от JUnit, вы также должны указатьimplementation под dependencies.

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

Другие вопросы по тегам