Como adiciono um novo conjunto de fontes ao Gradle?

99

Quero adicionar testes de integração à minha compilação do Gradle (versão 1.0). Eles devem ser executados separadamente dos meus testes normais porque exigem que um webapp seja implantado no localhost (eles testam esse webapp). Os testes devem ser capazes de usar classes definidas em meu conjunto de origem principal. Como faço isso acontecer?

Spina
fonte

Respostas:

114

Levei um tempo para descobrir e os recursos online não eram bons. Então, eu queria documentar minha solução.

Este é um script de compilação simples do Gradle que tem um conjunto de origem intTest além dos conjuntos de origem principal e de teste:

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
}
Spina
fonte
7
Você ainda precisará declarar e configurar uma tarefa de teste de integração. Em termos de documentação, há uma java/withIntegrationTestsamostra da distribuição completa do Gradle.
Peter Niederwieser
Obrigado @PeterNiederwieser. Corrigi meu script de compilação de amostra.
Spina
2
Eu estava tentando fazer isso também ... muito obrigado por postar a solução :)
Igor Popov
@PeterNiederwieser Obrigado - você poderia fazer um link? Eu também acho que essa situação exata está faltando em documentos: é muito bom definir um novo sourceSet, mas nenhuma informação sobre "ligar isso" aos destinos reais de compilação, jar, teste e outros enfeites - como este exemplo faz (exceto para adicionar no jar, ou fazendo um novo jar, a partir desse sourceSet).
stolsvik de
Na linha 6, recebo "Não é possível resolver o símbolo 'java'" ao usar o IntelliJ. Alguma ideia do porquê?
Snekse
33

Aqui está como consegui isso sem usar 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
}

Testado usando: Gradle 1.4 e Gradle 1.6

Mike Rylander
fonte
2
Obrigado por compartilhar! É bom ver implementações alternativas.
Spina
1
enquanto java { srcDir 'src/integrationtest/java' } resources { srcDir 'src/integrationtest/resources' }não é relevante, uma vez que apenas redeclares src/<sourceSetName>/...para src/integrationtest/...: aqui: mudar o T de capital a um menor t
childno͡.de
Cuidado com essa abordagem. compileClasspath += sourceSets.main.runtimeClasspathestá combinando dois conjuntos de arquivos. Não há resolução de conflito usual para dependências. Você pode acabar com duas versões da mesma biblioteca. Estender as configurações ajudará nisso.
chalimartines
20

Isso foi escrito para Gradle 2.x / 3.x em 2016 e está muito desatualizado !! Dê uma olhada nas soluções documentadas no Gradle 4 e superior


Para resumir as duas respostas antigas (obter o melhor e o mínimo viável de ambos os mundos):

algumas palavras calorosas primeiro:

  1. primeiro, precisamos definir sourceSet:

    sourceSets {
        integrationTest
    }
  2. em seguida, expandimos o sourceSetde test, portanto, usamos o test.runtimeClasspath(que inclui todas as dependências do próprio testAND test) como caminho de classe para o derivado sourceSet:

    sourceSets {
        integrationTest {
            compileClasspath += sourceSets.test.runtimeClasspath
            runtimeClasspath += sourceSets.test.runtimeClasspath // ***)
        }
    }
    • nota ) de alguma forma, essa redeclaração / extensão para sourceSets.integrationTest.runtimeClasspathé necessária, mas deve ser irrelevante, pois runtimeClasspathsempre expande output + runtimeSourceSet, não entenda
  3. definimos uma tarefa dedicada apenas para executar testes de integração:

    task integrationTest(type: Test) {
    }
  4. Configure o integrationTestuso de classes de teste e caminhos de classe. Os padrões do javaplugin usam otest sourceSet

    task integrationTest(type: Test) {
        testClassesDir = sourceSets.integrationTest.output.classesDir
        classpath = sourceSets.integrationTest.runtimeClasspath
    }
  5. (opcional) execução automática após o teste

    teste de integraçãoTest.dependsOn
    

  6. (opcional) adicionar dependência de check(para que sempre seja executado quando buildou checksão executados)

    tasks.check.dependsOn(tasks.integrationTest)
  7. (opcional) adicione recursos java, ao sourceSetpara oferecer suporte à detecção automática e criar esses "parciais" em seu IDE. ou seja, o IntelliJ IDEA criará automaticamente sourceSetdiretórios java e recursos para cada conjunto se ele não existir:

    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)

referindo-se a:

Infelizmente, o código de exemplo em github.com/gradle/gradle/subprojects/docs/src/samples/java/customizedLayout/build.gradle ou … / gradle /… / withIntegrationTests / build.gradle parece não lidar com isso ou tem um diferente / mais complexo / para mim nenhuma solução mais clara de qualquer maneira!

childno͡.de
fonte
1
(!) como se constatou, o uso único de aprimoramentos de sourceSet sem configurações ou resultados de saída em um erro de criação de ideia após a abertura inicial de um projeto. a dependência de compilação (aqui: test) para o novo "módulo" (aqui: integrationTest) não está disponível primeirocompileTestJava
childno͡.de
2
classesDirfoi migrado para classesDirsno gradle 5
deFreitas
obrigado pela dica @deFreitas, marquei a resposta como desatualizada
childno͡.de
9

O plugin nebula-facet elimina o clichê:

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

Para testes de integração especificamente, mesmo isso é feito para você , basta aplicar:

apply plugin: 'nebula.integtest'

Os links do portal do plug-in Gradle para cada um são:

  1. nebula.facet
  2. nebula.integtest
jkschneider
fonte
7

Se você está usando

Para fazer o IntelliJ reconhecer o conjunto de fontes personalizado como raiz de fontes de teste:

plugin {
    idea
}

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

Aqui está o que funciona para mim a partir do 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
}

A partir da versão 4.0, o Gradle agora usa diretórios de classes separados para cada idioma em um conjunto de origem. Portanto, se o seu script de construção usar sourceSets.integrationTest.output.classesDir, você verá o seguinte aviso de descontinuação.

O Gradle agora usa diretórios de saída separados para cada linguagem JVM, mas esta construção assume um único diretório para todas as classes de um conjunto de origem. Este comportamento foi preterido e está programado para ser removido no Gradle 5.0

Para se livrar desse aviso, basta alternar para sourceSets.integrationTest.output.classesDirs. Para obter mais informações, consulte as notas de versão do Gradle 4.0 .

Ryan Sobol
fonte
mudar para <hmm> ?? Seu antes e depois são os mesmos.
Merk
0

Sou novo no Gradle, usando o Gradle 6.0.1 JUnit 4.12. Aqui está o que eu criei para resolver esse problema.

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

dependencies {
    testImplementation 'junit:junit:4.12'
}

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

Observe que a fonte principal e a fonte de teste são referenciadas separadamente, uma abaixo maine uma abaixo test.

O testImplementationitem em dependenciesé usado apenas para compilar o código-fonte em test. Se o seu código principal realmente dependesse do JUnit, você também especificaria implementationsob dependencies.

Tive que especificar a repositoriesseção para fazer isso funcionar, duvido que seja a melhor / única maneira.

hoopyfrood
fonte