Running Integration Tests With Gradle

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.

This lesson assumes that:

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:

  1. Configure Gradle to use the Bintray’s JCenter Maven repository when it resolves the dependencies of our build script.
  2. Add the Gradle TestSets plugin dependency into the classpath configuration.

After we have configured the dependencies of our build script, our build.gradle file looks as follows:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13
14dependencies {
15    testCompile('junit:junit:4.12')
16}
17
18test {
19    useJUnit {
20        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
21    }
22    testLogging {
23        showStandardStreams = true
24    }
25}

Second, we have to apply the Gradle TestSets plugin. After we have done this, our build.gradle file looks as follows:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15dependencies {
16    testCompile('junit:junit:4.12')
17}
18
19test {
20    useJUnit {
21        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
22    }
23    testLogging {
24        showStandardStreams = true
25    }
26}

If we are using Gradle 2.1 or newer, we can configure the dependencies of our build script and apply the required plugins by using the plugins DSL. If we decide to do so, we have to add the following snippet into our build.gradle file:

1plugins {
2	id 'java'
3    id 'org.unbroken-dome.test-sets' version '1.2.0'
4}

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:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15testSets {
16    integrationTest
17}
18
19dependencies {
20    testCompile('junit:junit:4.12')
21}
22
23test {
24    useJUnit {
25        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
26    }
27    testLogging {
28        showStandardStreams = true
29    }
30}

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:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15testSets {
16    integrationTest { dirName = 'integration-test' }
17}
18
19dependencies {
20    testCompile('junit:junit:4.12')
21}
22
23test {
24    useJUnit {
25        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
26    }
27    testLogging {
28        showStandardStreams = true
29    }
30}

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 integrationTestCompile dependency 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:

 1dependencies {
 2    integrationTestCompile(
 3            //Add dependencies that are required to compile
 4            //our integration tests.
 5    )
 6    integrationTestRuntime(
 7            //Add dependencies that are required to run
 8            //our integration tests.
 9    )
10}

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:

 1import org.junit.Test;
 2import org.junit.experimental.categories.Category;
 3
 4@Category(IntegrationTest.class)
 5public class SampleIntegrationTest {
 6
 7    @Test
 8    public void sampleIntegrationTest() {
 9        System.out.println("Category: IntegrationTest");
10    }
11}

The IntegrationTest interface is a marker interface that identifies our integration tests. Its source code looks as follows:

1public interface IntegrationTest {
2}

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:

  1. Ensure that our integration tests are run before the check task and that the check task fails the build if an integration test fails.
  2. 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:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15testSets {
16    integrationTest { dirName = 'integration-test' }
17}
18
19check.dependsOn integrationTest
20integrationTest.mustRunAfter test
21
22dependencies {
23    testCompile('junit:junit:4.12')
24}
25
26test {
27    useJUnit {
28        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
29    }
30    testLogging {
31        showStandardStreams = true
32    }
33}

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:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15testSets {
16    integrationTest { dirName = 'integration-test' }
17}
18
19check.dependsOn integrationTest
20integrationTest.mustRunAfter test
21
22tasks.withType(Test) {
23    reports.html.destination = file("${reporting.baseDir}/${name}")
24}
25
26dependencies {
27    testCompile('junit:junit:4.12')
28}
29
30test {
31    useJUnit {
32        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
33    }
34    testLogging {
35        showStandardStreams = true
36    }
37}

Third, we have to configure the integrationTest task by following these steps:

  1. 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.
  2. Configure JUnit to run only integration tests that belong to the IntegrationTest category. We can do this by setting the fully qualified class name of the IntegrationTest interface as the value of the includeCategories JUnit configuration option.
  3. Ensure that Gradle prints the information that is written to System.out or System.err when our integration tests are run. By the way, we have to do this only because our integration test writes intormation to System.out.

After we have configured the integrationTest task, our build.gradle file looks as follows:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath(
 7            'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.2.0'
 8        )
 9    }
10}
11
12apply plugin: 'java'
13apply plugin: 'org.unbroken-dome.test-sets'
14
15testSets {
16    integrationTest { dirName = 'integration-test' }
17}
18
19check.dependsOn integrationTest
20integrationTest.mustRunAfter test
21
22tasks.withType(Test) {
23    reports.html.destination = file("${reporting.baseDir}/${name}")
24}
25
26dependencies {
27    testCompile('junit:junit:4.12')
28}
29
30test {
31    useJUnit {
32        includeCategories 'com.testwithspring.intermediate.unittests.UnitTest'
33    }
34    testLogging {
35        showStandardStreams = true
36    }
37}
38
39integrationTest {
40    useJUnit {
41        includeCategories 'com.testwithspring.intermediate.integrationtests.IntegrationTest'
42    }
43    testLogging {
44        showStandardStreams = true
45    }
46}

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:

 1$ gradle clean build -x integrationTest
 2:clean
 3:compileJava UP-TO-DATE
 4:processResources UP-TO-DATE
 5:classes UP-TO-DATE
 6:jar
 7:assemble
 8:compileTestJava
 9:processTestResources UP-TO-DATE
10:testClasses
11:test
12
13com.testwithspring.intermediate.unittests.SampleUnitTest >sampleUnitTest STANDARD_OUT
14    The category: UnitTest
15:check
16:build
17
18BUILD SUCCESSFUL
19
20Total 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:

 1$ gradle clean build -x test
 2:clean
 3:compileJava UP-TO-DATE
 4:processResources UP-TO-DATE
 5:classes UP-TO-DATE
 6:jar
 7:assemble
 8:compileIntegrationTestJava
 9:processIntegrationTestResources
10:integrationTestClasses
11:integrationTest
12
13com.testwithspring.intermediate.integrationtests.SampleIntegrationTest
14  > sampleIntegrationTest STANDARD_OUT
15    Category: IntegrationTest
16:check
17:build
18
19BUILD SUCCESSFUL
20
21Total 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:

 1$ gradle clean build
 2:clean
 3:compileJava UP-TO-DATE
 4:processResources UP-TO-DATE
 5:classes UP-TO-DATE
 6:jar
 7:assemble
 8:compileTestJava
 9:processTestResources UP-TO-DATE
10:testClasses
11:test
12
13com.testwithspring.intermediate.unittests.SampleUnitTest >sampleUnitTest STANDARD_OUT
14    The category: UnitTest
15:compileIntegrationTestJava
16:processIntegrationTestResources
17:integrationTestClasses
18:integrationTest
19
20com.testwithspring.intermediate.integrationtests.SampleIntegrationTest
21   > sampleIntegrationTest STANDARD_OUT
22    Category: IntegrationTest
23:check
24:build
25
26BUILD SUCCESSFUL
27
28Total 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.

Get the source code from Github