Jovana Mihaljcic
Jovana Mihaljcic

Reputation: 87

Separating integration tests in spring boot app

I am writing tests for SpringBoot application. I would like to separate integration tests from unit tests. Now my project structure looks something like this:

├── Demo
│   ├── src
│   │   ├── main
|   |   |   └──java
│   │   ├── test
|   |   |   └──java

Is there a way to add a module like this:

├── Demo
│   ├── src
│   │   ├── main
|   |   |   └──java
│   │   ├── integrationTest
|   |   |   └──java
│   │   ├── test
|   |   |   └──java

I would like that new integrationTest module to act the same as test module, but I don't know how to configure it. I managed to add it as module, mark integrationTest/java dir as Test Sources Root and run test in it but @SpringBootTest cannot resolve ApplicationContext, and all of my beans are always null.

When I write the same test in test module, it works fine.

Is there a way to do this? Is this the right way to separate integration tests? If not, what is the best practice?

I am working in intelliJ and I am using gradle as package manager.

Upvotes: 5

Views: 5202

Answers (2)

gz90
gz90

Reputation: 41

Building on @iboisver's comment, you can separate them and are encouraged to do so in the gradle docs. You basically have to:

  1. Create a new directory under src (i.e. src/integrationTest)
  2. Add the source set in the build.gradle file along with it's configurations:
sourceSets {
    integrationTest {
        compileClasspath += sourceSets.main.output + sourceSets.test.output
        runtimeClasspath += sourceSets.main.output + sourceSets.test.output
    }
}

configurations {
    integrationTestImplementation.extendsFrom testImplementation
    integrationTestRuntimeOnly.extendsFrom testRuntime
}
  1. Create an integrationTests task to run your integration tests, and attach it to the check task (also in build.gradle):
task integrationTest(type: Test) {
    description = 'Runs integration tests.'
    group = 'verification'

    testClassesDirs = sourceSets.integrationTest.output.classesDirs
    classpath = sourceSets.integrationTest.runtimeClasspath
    shouldRunAfter test
}

check.dependsOn integrationTest

I found a couple of very helpful articles (1, 2) that guided me on my own integration test setup.

NOTE: seems like the whole process is much simpler if you use the JVM Test Suite Plugin (requires Gradle 7.3+), but since it's in incubating state I didn't go with it.

Upvotes: 0

user4695271
user4695271

Reputation:

You can have them with the rest of the tests; apply a convention and tag-match that to filter them out, something like appending IntegrationTest to the class name(s) and using the same value for the JUnit @Tag... then just define/declare some Gradle tasks to execute them:

test {
  useJUnitPlatform()
}

task integrationTests(type: Test) {
  filter { includes = ["IntegrationTest"] }
  useJUnitPlatform()
}

task unitTests(type: Test) {
  filter { includes = ["UnitTest"] }
  useJUnitPlatform()
}

Full example:

package tld.domain.support;

public final class Category {
  public static final INTEGRATION_TEST = "IntegrationTest";

  public static final UNIT_TEST = "UnitTest";
}
import tld.domain.support.Category;

import org.junit.jupiter.api.Tag;
import org.junit.jupiter.api.Test;

@Tag(Category.INTEGRATION_TEST)
final class MyIntegrationTest {
  @Test
  void testFoo() {
    // ...
  }

Upvotes: 5

Related Questions