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

99

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

Спина
источник

Ответы:

114

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

Это простой скрипт сборки 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
}
Спина
источник
7
Вам все равно нужно будет объявить и настроить задачу тестирования интеграции. Что касается документации, java/withIntegrationTestsв полном дистрибутиве Gradle есть образец.
Peter Niederwieser
Спасибо @PeterNiederwieser. Я исправил свой пример скрипта сборки.
Спина
2
Я тоже пытался сделать это ... большое спасибо за размещение решения :)
Игорь Попов
@PeterNiederwieser Спасибо, не могли бы вы связать это? Я также считаю, что эта точная ситуация сильно отсутствует в документации: все хорошо и хорошо, когда определяется новый sourceSet, но нет информации о том, как «подключить это к» фактическим целям компиляции, jar, теста и прочего, как в этом примере (за исключением добавления в банку или сделайте новую банку из этого набора).
stolsvik
В строке 6 я получаю сообщение «Невозможно разрешить символ java» при использовании IntelliJ. Есть мысли о том, почему?
Snekse
33

Вот как я добился этого без использования 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.

Майк Райландер
источник
2
Спасибо, что поделился! Приятно видеть альтернативные реализации.
Spina
1
в то время как java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' }это не имеет значения , так как он просто redeclares src/<sourceSetName>/...к src/integrationtest/...: здесь: изменение капитала T на более низкую т
childno͡.de
Остерегайтесь такого подхода. compileClasspath += sourceSets.main.runtimeClasspathобъединяет два набора файлов. Обычного разрешения конфликтов для зависимостей нет. Вы можете получить две версии одной и той же библиотеки. В этом поможет расширение конфигураций.
chalimartines
20

Когда-то это было написано для Gradle 2.x / 3.x в 2016 году и сильно устарело !! Ознакомьтесь с документированными решениями в Gradle 4 и выше.


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

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

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

    sourceSets {
        integrationTest
    }
    
  2. затем мы расширяем sourceSetfrom test, поэтому мы используем test.runtimeClasspath(который включает все зависимости от самого testAND 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тестовые классы и пути к классам. По умолчанию из javaплагина используетсяtest sourceSet

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

    integrationTest.dependsOn test
    

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

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

    sourceSets {
         integrationTest {
             java
             resources
         }
    }
    

tl; dr

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)

ссылаясь на:

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

childno͡.de
источник
1
(!) Как оказалось, однократное использование расширений sourceSet без конфигураций или вывода приводит к ошибке make после первоначального открытия проекта. зависимость сборки (здесь: test) для нового «модуля» (здесь: integrationTest) недоступна с первого compileTestJava
раза
2
classesDirбыл перенесен classesDirsна Gradle 5
deFreitas
спасибо за подсказку @deFreitas, я пометил ответ как устаревший
childno͡.de
9

Туманность фасетки плагина устраняет шаблонный:

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

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

apply plugin: 'nebula.integtest'

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

  1. nebula.facet
  2. nebula.integtest
Jkschneider
источник
7

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

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

plugin {
    idea
}

idea {
    module {
        testSourceDirs = testSourceDirs + sourceSets["intTest"].allJava.srcDirs
        testResourceDirs = testResourceDirs + sourceSets["intTest"].resources.srcDirs
    }
}
Jenglert
источник
2

Вот что у меня работает с 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 .

Райан Соболь
источник
переключиться на <hmm> ?? Ваши до и после одинаковы.
Merk
-1

Я новичок в 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раздел, чтобы заставить это работать, я сомневаюсь, что это лучший / единственный способ.

хупифрод
источник