IntelliJ integration test in separate folder libraries not found: Springboot with Gradle project configuration problem

Viewed 724

I have an intelliJ Springboot Gradle project with the following structure:

MyProject
├── build.gradle
└── src
    ├── integration (integration test sources root)
    │   ├── java 
    │   │   └── com...
    │   └── resources
    │
    ├── main (sources root)
    │   ├── java
    │   │   └── com...
    │   └── resources
    │
    ├── test (test sources root)
    │   └── java
    │       └── com...
    │...

My build.gradle is like the following:

plugins {
    id 'org.springframework.boot' version '2.4.3'
    id 'io.spring.dependency-management' version '1.0.11.RELEASE'
    id 'java'
}

group = 'java.bike'
version = '0.0.1-SNAPSHOT'
sourceCompatibility = '8'

configurations {
    compileOnly {
        extendsFrom annotationProcessor
    }
}

sourceSets {
    integration {
        compileClasspath += main.output + test.output
        runtimeClasspath += main.output + test.output
        java.srcDirs('./src/integration/java')
        resources.srcDirs('./src/integration/resources')
    }
}

task integrationTest(type: Test) {
    description = 'Runs the integration tests.'
    group = 'verification'
    testClassesDirs = sourceSets.integration.output.classesDirs
    classpath = sourceSets.integration.runtimeClasspath
    outputs.upToDateWhen { false }
    // This is not needed, but I like to see which tests have run
    testLogging { events "passed", "skipped", "failed" }
    // mustRunAfter test
}

tasks.withType(Test) {
    useJUnitPlatform()
}

repositories {
    mavenCentral()
}

dependencies {
    implementation 'org.springframework.boot:spring-boot-starter-data-jpa'
    implementation 'org.springframework.boot:spring-boot-starter-web'
    developmentOnly 'org.springframework.boot:spring-boot-devtools'
    runtimeOnly 'org.postgresql:postgresql'
    testImplementation 'org.springframework.boot:spring-boot-starter-test'
    testImplementation 'org.assertj:assertj-core'
}

Now, I've got a couple of Unit tests in src/test, they work perfectly.

However, for the Integration tests, like:

package com.bike;

import org.junit.jupiter.api.Test;
import org.springframework.boot.test.context.SpringBootTest;

@SpringBootTest
class BorrowMyBikeApplicationTests {

    @Test
    void contextLoads() {
    }
}

It cannot find any libraries in the classpath, so for instance for @SpringBootTest it suggests Add library Gradle:spring-boot-test:2.4.3 to Classpath, and for @Test the suggestion is Add JUnit4/5 to classpath.

Identical test placed in the src/test works without a hitch.

Granted I could go along with these suggestions, but then I'd have to add these dependencies every time I checkout the project. I much prefer it worked for the integration folder the same way it works for the test folder.

What am I missing and how that configuration could be done to work out of the box?

1 Answers

Trawling through https://docs.gradle.org/current/userguide/java_testing.html#sec:configuring_java_integration_tests, I've found the answer:

I was missing configuration for integration tests, as in:

configurations {
    integrationImplementation.extendsFrom testImplementation
    integrationRuntimeOnly.extendsFrom testRuntimeOnly
} 

do note integrationImplementation.extendsFrom should be the [name of your integration test sourceSet]Implementation.extedsFrom (in my case intgergation), same for integrationRuntimeOnly.extendsFrom

Optional: you can also extend your sourceSets (It seems to work even without, but I find it cleaner this way):

sourceSets {
    main {
        java.srcDirs('./src/main/java')
        resources.srcDirs('./src/main/resources')
    }
    test {
        java.srcDirs('./src/test/java')
        resources.srcDirs('./src/test/resources')
    }
    integration {
        compileClasspath += sourceSets.main.output
        runtimeClasspath += sourceSets.main.output
        java.srcDirs('./src/integration/java')
        resources.srcDirs('./src/integration/resources')
    }
}
Related