Your Gradle project can easily be setup to run integration tests using a specific Gradle task and source directory. This separates the integration tests from unit tests, making the project easier to understand and helping developers to work more productively.

In this article you’ll learn the simplest way to run integration tests in your Gradle project by adding just a few lines of code to your build script.

Benefits of integration tests

Integration tests are just one part of an overall testing strategy. Depending on who you ask, the term integration test may mean something completely different.

  • a monolith application developer might tell you that integration tests verify that multiple classes or modules work together as expected
  • a microservice developer might tell you that integration tests verify that multiple independently deployed services work together as expected

Thankfully, you and your team are free to choose your own definition!

But whatever you decide, can we at least agree that integration tests are different from unit tests? Unit tests verify the functionality of a specific class independently.

Being able to run integration tests separately from unit tests has several advantages, which we’ll explore later in the article. But first, how can we set it up in Gradle?

Setup your Gradle project for integration tests

The Gradle documentation already has a very good explanation of how to configure integration tests in a project from scratch, using only the Gradle APIs and no additional plugins.

This involves the following tasks:

  1. create a source set for the integration tests. This is a separate directory in which to put the integration test classes and resources.
  2. setup dependencies for the source set so that, for example, in the integration tests you have access to the same dependencies as the main production code
  3. configure the compilation and runtime classpath for the source set to include the production code you want to test (always useful to be able to access the thing you want to test!)
  4. create an integration test task which lets you to run integration tests on their own from the command line

Sounds like a lot of work right? 🥺 That’s why my preference is to use a plugin to do all of this setup automatically.

TestSets plugin (Gradle version up to 7.2)

The TestSets plugin does just this, letting you configure all the above steps with just a few lines of code.

Apply the plugin to your Gradle project (all code snippets below use the Groovy DSL).

plugins {
    id 'org.unbroken-dome.test-sets' version '4.0.0'
}

The plugin lets you name your group of tests however you want. For example you could have integration tests, performance tests, or even end-to-end tests. We’ll stick with integration tests though, so we need to configure the plugin as follows.

testSets {
    integrationTest
}

With just these three lines of code, you get the following goodies in your Gradle project:

  1. a source set called integrationTest ready for you to add classes under src/integrationTest/java or resources under src/integrationTest/resources.
  2. dependency configurations integrationTestImplementation and integrationTestRuntimeOnly so you can add integration test specific dependencies. For example, if you’re using a particular framework for integration testing (e.g. WireMock), you can add it here.
  3. a test task integrationTest for actually getting those tests run

Now when you run ./gradlew integrationTest it runs the integration tests.

Of course you can still run the unit tests with ./gradlew test or ./gradlew check. Note that the check task won’t run the integration tests unless you specifically setup a task dependency to do that.

tasks.named('check') {
    dependsOn tasks.named('integrationTest')
}

This is a good idea to make sure the integration tests are not forgotten. Since the build task depends on check, you can configure your continuous integration server to run ./gradlew build and know your integration tests will be run.

You can find a sample project over in this GitHub repository.

JVM Test Suite Plugin (Gradle version 7.3+)

Gradle have now plugged the gap with their own plugin to achieve the same outcome, called the JVM Test Suite plugin. If you’re using Gradle 7.3+ then I recommend this plugin over the TestSets plugin, as it will likely become the standard for setting up integration tests.

The plugin gets applied automatically when the java plugin is applied, so in our example we just need to configure it. This involves configuring whatever test suites we need, in our case for integration tests.

testing {
    suites {
        integrationTest(JvmTestSuite) {
            dependencies {
                implementation project
            }
        }
    }
}

This configuration creates an integrationTest source set, integration test dependency configurations, and an integrationTest task.

And like before we can ensure the integration tests run whenever the check task runs.

tasks.named('check') {
    dependsOn testing.suites.integrationTest
}

One nice thing this plugin does that the TestSets plugin doesn’t do, is to automatically add the relevant JUnit JUpiter dependencies on the integration test runtime and compile classpaths. If you want to use JUnit 4 instead, just call useJUnit() within your test suite closure.

Advantages to developer workflow

Running integration tests separately from unit tests and putting them in a different directory has some advantages when in comes to the daily grind of software development.

Faster feedback

Integration tests are often slower than unit tests, especially when you include layers like the network and database. Being able to run unit tests alone means you can more frequently run them during development to ensure you’re not breaking functionality as you go.

You might choose to run the integration tests less frequently, perhaps before pushing code changes.

Cleaner codebase

Using convention to distinguish unit tests from integration tests helps developers understand what context they’re working in. One way is to use a particular naming convention e.g. <classs under test>IntegrationTest. But probably better still is to use the approach shown above, which not only provides strong separation, but offers the ability to treat the source differently e.g. declaring specific integration test only dependencies.

Running other types of tests

Using a separate source directory for integration and unit tests also paves the way for other types of tests you might want to add in the same way.

Here are some examples:

  • performance tests
  • end-to-end tests
  • contract tests

What types of tests you need depends on your application. The test pyramid approach used to be very popular, with a few end-to-end tests stacked on more integration tests, on top of even more unit tests.

Test pyramid

The test pyramid can be useful in some scenarios, but don’t let it stop you trying something different

But it doesn’t always help to try to fit a square peg into a round hole, so there are now other approaches that may work better for front-end apps or microservice architectures, such as Spotify’s test honeycomb. 🐝

For a full exploration of the approaches, check out this guide to testing towards modern frontend and backend apps. The key takeaway is that you and your team get to decide how best to test your application, and you don’t have to follow what some agile guru may have said ten years ago.

Depending on what technology you choose for your other test layers, you may or may not want to use the TestSets plugin as described above.

For example, to run performance tests using the Gatling framework you apply the Gatling Gradle plugin, which automatically adds a source set named gatling. In this case, there’s no need to also apply the TestSets plugin.

Final thoughts

Adding integration tests to a Gradle project is already a well-documented process, but using the TestSets or JVM Test Suite plugins makes this configuration even easier. Consider applying one of them to your project to simplify writing and running integration tests.

Video

Check out the accompanying video from the Tom Gregory Tech YouTube channel.