Reputation: 87
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
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:
src
(i.e. src/integrationTest
)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
}
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
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