Integration Testing With Gradle
This guide shows you how to configure Gradle to use any kind of tests and run them independently from others.
Join the DZone community and get the full member experience.
Join For FreeUnit testing works automatically using Gradle, but if you would like to have a separate set of integration tests you need to do a small exercise. Actually they don’t have to be integration tests at all. This guide shows you how to configure Gradle to use any kind of tests and run them independently from others. I will use Scala language here but the same works for any JVM language.
The Goal
We are about to define a new Gradle task named itest which will run only tests implemented in a specific folder “src/itest/scala”. The standard built-in task test will work without any change running only tests in “src/test/scala” directory.
Standard Java/Scala Project
We will start with a standard Gradle Java or Scala project. The programming language doesn’t matter here. Typically the directory structure looks like this:
<project root>
+ src
+ main
+ scala
+ test
+ scala
- build.gradle
Main source code (being tested) resides in “src/main/scala” and all unit tests are in “src/test/scala”.
Where to Put Integration Test Classes and How to Name Them
We already know where our unit tests are. A good habit is to name them using by the class they test, followed by “Test” or “Spec” suffix. For example if the tested class is named “Miracle” then unit tests for it should go to a class named “MiracleSpec” (or MiracleTest if you like). It’s just a convention, nothing more.
We will use the same principle for integration tests but we will put them inside “src/itest/scala” directory and use “ITest” or “ISpec” suffix. This is also a convention, but it allows us to run them separately from unit tests.
Why a Special Directory and Also a Special Name Suffix
I recommend to put integration tests physically to a different directory and also use a different naming pattern so that you can distinguish the tests from the rest of your code in many other cases.
For example if you package the whole application into a one big fat JAR and you want to run integration tests only. How would you do that? Some test runners support filtering by class/file name only. You would use “*ISpec” regular expression to achieve it.
Another example is that it is very convenient to right-click a directory in your favourite IDE (IntelliJ IDEA for example) and run all tests inside the directory. Also IDEA allows you to run tests by providing class name pattern which is the reason why I like to use different suffixes for integration and unit tests.
Example Project Structure
Imagine a Scala project with one implementation class named Fujara (an awesome Slovak musical instrument). Its unit tests are in FujaraSpec class and integration tests in FujaraISpec. Often we need some data for integration tests (itest-data.xml) or logging configuration (logback-test.xml) different from the main application logging configuration.
<project root>
+ src
+ itest
+ resources
+ com
+ buransky
- itest-data.xml
logback-test.xml
+ scala
+ com
+ buransky
- FujaraISpec.scala
+ main
+ resources
- logback.xml
+ scala
+ com
+ buransky
- Fujara.scala
+ test
+ scala
+ com
+ buransky
- FujaraSpec.scala
- build.gradle
The build.gradle
I am using Gradle 2.4 but this solution has worked for older versions too. I am not going to provide complete build script, but only the parts relevant to this topic.
configurations {
itestCompile.extendsFrom testCompile
itestRuntime.extendsFrom testRuntime
}
sourceSets {
itest {
compileClasspath += main.output + test.output
runtimeClasspath += main.output + test.output
// You can add other directories to the classpath like this:
//runtimeClasspath += files('src/itest/resources/com/buransky')
// Use "java" if you don't use Scala as a programming language
scala.srcDir file('src/itest/scala')
}
// This is just to trick IntelliJ IDEA to add integration test
// resources to classpath when running integration tests from
// the IDE. It's is not a good solution but I don't know about
// a better one.
test {
resources.srcDir file('src/itest/resources')
}
}
task itest(type: Test) {
testClassesDir = sourceSets.itest.output.classesDir
classpath = sourceSets.itest.runtimeClasspath
// This is not needed, but I like to see which tests have run
testLogging {
events "passed", "skipped", "failed"
}
}
Run Integration Tests
Now we should be able to run integration test simply by running “gradle itest” task. In our example it should run FujaraISpec only. To run unit tests in FujaraSpec, execute “gradle test”.
Define Other Test Types
If you would like to use the same principle for functional tests, performance tests, acceptance tests, or whatever tests, just copy&paste the code above and replace “itest” with “ftest”, “ptest”, “atest”, “xtest”, …
Published at DZone with permission of Rado Buranský, DZone MVB. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments