My previous blog post described how we can add integration tests to our Gradle build.

A few days after I had published that blog post, I learned that we don’t have to do everything from the scratch (thanks David) because we can simplify our build script by using the Gradle TestSets plugin.

This blog post describes how we can add integration tests to our Gradle build, remove the unnecessary clutter from our build.gradle file, and fulfil the requirements specified in my previous blog post.

Let’s get started.

The example application of this blog post is tested with Gradle 4.6.

Additional Reading:

If you are not familiar with Gradle, you should read the following blog posts before you continue reading this blog post:

Applying the Gradle TestSets Plugin

Before we can use the Gradle TestSets plugin, we have to apply it. We can do this by following this two-step process:

We can use the Gradle TestSets plugin only if we also using the java and/or groovy plugin.

First, we have to configure the dependencies of our build script. We can do this 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 TestSets plugin dependency to the classpath configuration.

The relevant part of our build.gradle file looks as follows:

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath 'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.4.5'
 7    }
 8}
 9
10apply plugin: 'application'
11apply plugin: 'java'

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

 1buildscript {
 2    repositories {
 3        jcenter()
 4    }
 5    dependencies {
 6        classpath 'org.unbroken-dome.gradle-plugins:gradle-testsets-plugin:1.4.5'
 7    }
 8}
 9
10apply plugin: 'application'
11apply plugin: 'java'
12apply plugin: 'org.unbroken-dome.test-sets'

If you are using Gradle 2.1 or newer, and you want to use the new plugins DSL, you can apply the Gradle TestSets plugin by adding the following snippet to your build.gradle file:

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

Additional Reading:

Let’s move on and find out how we can add a new test set to our Gradle build.

Adding a New Test Set to Our Build

We can create a new test set called integrationTest by adding the following snippet to our build.gradle file:

1testSets {
2    integrationTest
3}

After we have done this, the TestSets plugin adds the following “features” to our Gradle build:

  • It adds a source set named 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.
  • It adds two new dependency configurations to our build.
    • 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.
  • It adds two new tasks to our Gradle build:
    • The integrationTest task will run our integration tests.
    • The integrationTestJar task will package our integration tests to a jar file.

However, there is still one problem left. The requirements of our Gradle build states that:

  • The integration tests must be found from the src/integration-test/java directory.
  • The resources of our integration tests must be found from the src/integration-test/resources directory.

In other words, we have to change the directory name from integrationTest to integration-test. We can do this by specifying the value of the dirName property. We can specify that value by adding the following snippet to our build.gradle file:

1testSets {
2    integrationTest { dirName = 'integration-test' }
3}
If you are using Android Studio and you want to navigate between the integration test code and the code under test, you can define your source set in a way that is described in this comment.

Let’s move on and add some dependencies to our new dependency configurations.

Declaring the Dependencies of Our Integration Tests

We can now add dependencies to the integrationTestCompile and integrationTestRuntime dependency configurations. For example, because the integration tests of our example applications use AssertJ 3.0, we have to add the assertj-core dependency to the integrationTestCompile configuration. After we have done this, the dependencies build script block of our build.gradle file looks as follows:

1dependencies {
2    compile 'log4j:log4j:1.2.17'
3    testCompile 'junit:junit:4.11'
4    integrationTestCompile 'org.assertj:assertj-core:3.0.0'
5}

Let’s move on and find out how we can configure the task that runs our integration tests.

Configuring the Integration Test Task

Although the Gradle TestSets plugin created the integrationTest task when we created our test set, we have to make some changes to its configuration if we want to fulfil the requirements of our Gradle build.

To be more specific, 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 following these steps:

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

We can do these configuration changes by adding the following lines to our build.gradle file:

1check.dependsOn integrationTest
2integrationTest.mustRunAfter test

Gradle skips tasks whose input and output are up to date. This means that if we run our integration tests twice without making any changes, our integration tests are run only once. Because we did not make any changes before we tried to run them for the second time, Gradle skips the integrationTest task because its input and output are up to date.

If we want to run our integration tests every time when the integrationTest task is invoked, we have to tell Gradle that the outputs of the integrationTest task should always be considered out of date.

A Gradle task has a property called outputs, and the type of this property is TaskOutputs. If we want that the outputs of the integrationTest task are always considered out of date, we have to ensure that that the upToDateWhen() method of the TaskOutputs interface always returns false. We can do this by adding the following code to our build.gradle file:

1project.integrationTest {
2    outputs.upToDateWhen { false }
3}

Additional Reading:

Let’s move on and find out how we can run our unit and integration tests.

Running Our Unit and Integration Tests

We have now created a new test set and configured the task that runs our integration tests. This means that we can finally run both unit and integration tests. The requirements of our build states that we must be able to run only unit tests, only integration tests, or all tests.

First, if we want to run only unit tests, we can use one of these two options:

  • We can run our unit tests by running the command: gradle clean test at the command prompt.
  • We can run our build and exclude integration tests by running the command: gradle clean build -x integrationTest at the command prompt.

Second, if we want to run only integration tests, we can choose one of the following options:

  • We can run our integration tests by running the command: gradle clean integrationTest at the command prompt.
  • We can run our build and exclude unit tests by running the command: gradle clean build -x test at the command prompt.

Third, if we want to run all tests, we can use one of these two options:

  • We can run our unit and integration tests by running the command: gradle clean test integrationTest at the command prompt.
  • We can run our build by running the command: gradle clean build at the command prompt.

When we run our tests, Gradle creates the HTML reports of our unit and integration tests to the following directories:

  • The build/reports/tests/integrationTest directory contains the HTML report that contains the test results of our integration tests.
  • The build/reports/tests/test directory contains the HTML report that contains the test results of our unit tests.

Let’s move on and summarize what we learned from this blog post.

Summary

This blog post has taught us four things:

  • When we create a new test set, the Gradle TestSets plugin creates a new source set, creates dependency configurations for the created test set, and creates the task that runs the tests found from the created test set.
  • We can configure the directory name of the created test set by setting the value of the dirName property.
  • We can configure the order in which our tasks are invoked.
  • We can exclude tasks by using the -x command line option.

P.S. You can get the example application of this blog post from Github.

If you want learn how to use Gradle for running your unit, integration, and end-to-end tests, which ensure that your Spring web application is working as expected, take a look at my upcoming Test With Spring Course.