After we have finished this lesson, we
- Can add custom test sets into our Gradle build.
- Know how we can declare the dependencies of our integration tests.
- Understand how we can run our integration tests with Gradle.
- You are familiar with JUnit 4
- You can use custom test runners
- You know how you can run unit tests by using Gradle
The Requirements of Our Gradle Build
The requirements of our Gradle build are:
- Our integration tests must have a separate source directory. The src/integration-test/java directory must contain the source code of our integration tests.
- Our integration tests must have a separate resource directory. The src/integration-test/resources directory must contain the resources of our integration tests.
- We must be able to run either unit tests, integration tests, or all tests.
- If an integration test fails, our build must fail as well.
- Integration and unit tests must have different HTML report directories.
Let’s start by adding a new test set into our Gradle build.
Adding Test Sets Into Our Gradle Build
We can add new test sets into our Gradle build by using the Gradle TestSets plugin. Before we will apply this plugin, we have to know that we can use this plugin only if we are also using the java and/or groovy plugin.
We can apply the Gradle TestSets plugin by following these steps:
First, we have to declare the dependencies of our build script by following these steps:
- Configure Gradle to use the Bintray’s JCenter Maven repository when it resolves the dependencies of our build script.
- Add the Gradle TestSets plugin dependency into the
classpathconfiguration.
After we have configured the dependencies of our build script, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
Second, we have to apply the Gradle TestSets plugin. After we have done this, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
plugins {
id 'java'
id 'org.unbroken-dome.test-sets' version '1.2.0'
}
Additional Reading:
Our next step is to configure the source and resource directories of our integration tests.
Configuring the Source and Resource Directories of Our Integration Tests
We can configure the source and resource directories of our integration tests by following these steps:
First, we have to add a new test set into our Gradle build. After we have done this, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
testSets {
integrationTest
}
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
This configuration adds a source set called integrationTest to our build. This means that the src/integrationTest/java directory contains the source code of our our integration tests and the src/integrationTest/resources directory contains the resources of our integration tests.
Second, we have to change the name of the root directory from integrationTest to integration-test. We can do this by specifying the value of the dirName configuration option.
After we have changed the name of the root directory, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
testSets {
integrationTest { dirName = 'integration-test' }
}
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
Let’s move on and find out how we can declare the dependencies of our integration tests.
Declaring the Dependencies of Our Integration Tests
When we added a new test set into our build, the Gradle TestSets plugin created two dependency configurations that are described in the following:
- The
integrationTestCompiledependency configuration contains the dependencies that are required to compile our integration tests. It also contains all dependencies that are required to compile our unit tests. - The integrationTestRuntime dependency configuration contains the dependencies that are needed when our integration tests are run. It also contains all dependencies that are required to compile our integration tests and to run our unit tests.
In other words, when we want to configure the dependencies of our integration tests, we have to add the following snippet into our build.gradle file:
dependencies {
integrationTestCompile(
//Add dependencies that are required to compile
//our integration tests.
)
integrationTestRuntime(
//Add dependencies that are required to run
//our integration tests.
)
}
Let’s move on and write one integration test.
Writing a Simple Integration Test
The SampleIntegrationTest class contains one integration test that writes the string: ‘Category: IntegrationTest’ to System.out. Because we want to configure the category of this test class, we have to annotate it with the @Category annotation.
The source code of our test class looks as follows:
import org.junit.Test;
import org.junit.experimental.categories.Category;
@Category(IntegrationTest.class)
public class SampleIntegrationTest {
@Test
public void sampleIntegrationTest() {
System.out.println("Category: IntegrationTest");
}
}
The IntegrationTest interface is a marker interface that identifies our integration tests. Its source code looks as follows:
public interface IntegrationTest {
}
Next, we have to configure the task that runs our integration tests.
Configuring the Task That Runs Our Integration Test
When we added a test set called integrationTest into our build, the Gradle TestSets plugin created a task called integrationTest that runs our integration tests. However, because we need to fulfill the requirements of our Gradle build, we have to make some changes to its configuration. We can make these changes by following these steps:
First, we have to ensure that unit tests are run before integration tests and that integration tests are run when we invoke the build task. We can do this by following these steps:
- Ensure that our integration tests are run before the
checktask and that thechecktask fails the build if an integration test fails. - Ensure that our unit tests are run before our integration tests. This guarantees that our unit tests are run even if our integration tests fail.
After we have made these changes, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
testSets {
integrationTest { dirName = 'integration-test' }
}
check.dependsOn integrationTest
integrationTest.mustRunAfter test
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
Second, we have to ensure that the HTML reports of unit and integration tests are written to separate report directories. If we don’t do this, the HTML reports of our unit and integration tests are created to the same report directory. In other words, if we run both unit and integration test, we can see only the HTML report that contains the test results of our integration tests.
We can configure the report directory of a task whose type is Test by setting the value of the reports.html.destination configuration option. Because we want to use separate reporting directories, we have to append the name of invoked task to the reporting base directory.
After we have done this, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
testSets {
integrationTest { dirName = 'integration-test' }
}
check.dependsOn integrationTest
integrationTest.mustRunAfter test
tasks.withType(Test) {
reports.html.destination = file("${reporting.baseDir}/${name}")
}
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
Third, we have to configure the integrationTest task by following these steps:
- Ensure that our integration tests are run by JUnit. Even though JUnit is enabled by default, we have to do this because we want to make changes to the JUnit configuration.
- Configure JUnit to run only integration tests that belong to the
IntegrationTestcategory. We can do this by setting the fully qualified class name of theIntegrationTestinterface as the value of theincludeCategoriesJUnit configuration option. - Ensure that Gradle prints the information that is written to
System.outorSystem.errwhen our integration tests are run. By the way, we have to do this only because our integration test writes intormation toSystem.out.
After we have configured the integrationTest task, our build.gradle file looks as follows:
buildscript {
repositories {
jcenter()
}
dependencies {
classpath(
'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
)
}
}
apply plugin: 'java'
apply plugin: 'org.unbroken-dome.test-sets'
testSets {
integrationTest { dirName = 'integration-test' }
}
check.dependsOn integrationTest
integrationTest.mustRunAfter test
tasks.withType(Test) {
reports.html.destination = file("${reporting.baseDir}/${name}")
}
dependencies {
testCompile('junit:junit:4.12')
}
test {
useJUnit {
includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
}
testLogging {
showStandardStreams = true
}
}
integrationTest {
useJUnit {
includeCategories 'com.testwithspring.intermediate.integrationtests.IntegrationTest'
}
testLogging {
showStandardStreams = true
}
}
Let’s move on and find out how we can run our unit and integration tests.
Running Unit and Integration Tests
We can run our tests by using one of the following options:
First, if we want to run only unit tests, we can use one of these two options:
- We can run unit tests by running the command: gradle clean test at command prompt.
- If we want to run our build and exclude integration tests, we have to run the command: gradle clean build -x integrationTest at command prompt.
When we run our unit tests, we should see an output that looks as follows:
$ gradle clean build -x integrationTest
:clean
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
com.testwithspring.intermediate.unittests.SampleUnitTest >sampleUnitTest STANDARD_OUT
The category: UnitTest
:check
:build
BUILD SUCCESSFUL
Total time: 1.287 secs
Second, if we want to run only integration tests, we can use one of these two options:
- We can run integration tests by running the command: gradle clean integrationTest at command prompt.
- We can run our build and exclude unit tests by running the command: gradle clean build -x test at command prompt.
When we run our integration tests, we should see an output that looks as follows:
$ gradle clean build -x test
:clean
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileIntegrationTestJava
:processIntegrationTestResources
:integrationTestClasses
:integrationTest
com.testwithspring.intermediate.integrationtests.SampleIntegrationTest
> sampleIntegrationTest STANDARD_OUT
Category: IntegrationTest
:check
:build
BUILD SUCCESSFUL
Total time: 1.304 secs
Third, if we want to run all tests, we can use one of these two options:
- We can run unit and integration tests by running the command: gradle clean test integrationTest at command prompt.
- We can run our build by running the command: gradle clean build at command prompt.
When we run all tests, we should see an output that looks as follows:
$ gradle clean build
:clean
:compileJava UP-TO-DATE
:processResources UP-TO-DATE
:classes UP-TO-DATE
:jar
:assemble
:compileTestJava
:processTestResources UP-TO-DATE
:testClasses
:test
com.testwithspring.intermediate.unittests.SampleUnitTest >sampleUnitTest STANDARD_OUT
The category: UnitTest
:compileIntegrationTestJava
:processIntegrationTestResources
:integrationTestClasses
:integrationTest
com.testwithspring.intermediate.integrationtests.SampleIntegrationTest
> sampleIntegrationTest STANDARD_OUT
Category: IntegrationTest
:check
:build
BUILD SUCCESSFUL
Total time: 1.833 secs
Let’s summarize what we learned from this lesson.
Summary
This lesson has taught us three things:
- We can add custom test sets into our Gradle build by using the Gradle TestSets plugin.
- The Gradle TestSets plugin creates dependency configurations that we can use when we declare the dependencies of our integration tests.
- When we add a new test set into our Gradle build, the Gradle TestSets plugin creates a task that runs the tests which belong to our custom test set.