Gradle is a build tool that allows you to create declarative, maintainable, concise and highly-performing builds. More importantly, in this context, Gradle gives you all the freedom you need instead of imposing a rigid build lifecycle on you. You'll get a glimpse of just how flexible Gradle can be by learning how to integrate Arquillian into a Gradle build.
We'll be contrasting two strategies for running Arquillian tests from Gradle:
- Container-specific test tasks
- Test "profiles" via build fragment imports
The first strategy is the recommended one since it gives you the benefit of being able to run your tests on multiple containers in the same build. However, the second approach is less esoteric and will be more familiar to Maven users. Of course, Gradle is so flexible that there are likely other solutions for this problem. We invite you to give us feedback if you find a better way (or another way worth documenting).
Let's get the common build stuff out of the way, then dive into the two strategies listed above.
The simplest Gradle build for a Java project is a sparse one line.
Put this line into a file named build.gradle at the root of the project, which is the standard location of the Gradle build file. (Perhaps after seeing this configuration you'll understand the reference in the section title).
Next we'll add the Maven Central and JBoss Community repository definitions, so that we can pull down dependent libraries. The latter repository hosts the Arquillian artifacts.
If your SCM (e.g., SVN, Git) is already ignoring the target directory, you may want to move the Gradle build output underneath this folder, rather than allowing Gradle to use it's default build directory, build. Let's add that configuration to the common build logic as well:
|If you are using Gradle alongside Maven, you shouldn't set the buildDir to target since Gradle organizes compiled classes different than Maven does, possibly leading to conflicts (Though, the behavior of Gradle can also be customized).|
We also recommend that you centralize version numbers at the top of your build to make upgrading your dependency easy. This list will grow as you add other containers, but we'll seed the list for the examples below:
We also need to add the unit test library (JUnit or TestNG) and the corresponding Arquillian integration:
In this example, we'll assume the project is compiling against APIs that are provided by the target container runtime, so we need to add a dependency configuration (aka scope) to include libraries on the compile classpath but excluded from the runtime classpath. In the future, Gradle will include support for such a scope. Until then, we'll define one ourselves in the configurations closure.
We also need to add the dependencies associated with that configuration to the compile classpaths using the sourceSets closure:
Here's the Gradle build all together now:
Now that the foundation of a build is in place (or you've added these elements to your existing Gradle build), we are ready to configuring the container-specific test tasks. In the first approach, we'll create a unique dependency configuration and task for each container.
Each project in Gradle is made up of one or more tasks. A task represents some atomic piece of work which a build performs. Examples include compiling classes, executing tests, creating a JAR, publishing an artifact to a repository. We are interested in the executing tests task. But it's not necessarily just a single test task. Gradle allows you to define any number of test tasks, each having its own classpath configuration. We'll use this to configure test executions for each container.
Let's assume that we want to run the tests against the following three Arquillian-supported containers:
- Weld EE Embedded 1.1
- Remote JBoss AS 6
- Embedded GlassFish 3
We'll need three components for each container:
- Dependency configuration (scope)
- Runtime dependencies
- Custom test task
We'll start with the Weld EE Embedded container. Starting from the Gradle build defined in the previous section, we first define a configuration for the test runtime dependencies.
Next we add the dependencies for compiling against the Java EE API and running Arquillian tests in the Weld EE Embedded container:
Finally, we define the test task:
This task will execute in the lifecycle setup by the Java plugin in place of the normal test task. You run it as follows:
Or, more simply:
Now we just repeat this setup for the other containers.
|Since you are creating custom test tasks, you likely want to configure the default test task to either exclude Arquillian tests are to use a default container, perhaps Weld EE Embedded in this case.|
Here's the full build file with the tasks for our three target containers:
|Notice we've added an extra resources directory for remote JBoss AS 6 to include the required jndi.properties file. That's a special configuration for the remote JBoss AS containers, though won't be required after Arquillian 1.0.0.Alpha4.|
It's now possible to run the Arquillian tests against each of the three containers in sequence using this Gradle command (make sure a JBoss AS is started in the background):
Pretty cool, huh?
Now let's look at another way to solve this problem.
Another way to approach integrating Arquillian into a Gradle build is to emulate the behavior of Maven profiles. In this case, we won't be adding any extra tasks, rather overriding the Java plugin configuration and provided tasks.
|A Maven profile effectively overrides portions of the build configuration and is activated using a command option (or some other profile activation setting).|
Once again, let's assume that we want to run the tests against the following three Arquillian-supported containers:
- Weld EE Embedded 1.1
- Remote JBoss AS 6
- Embedded GlassFish 3
All we need to do is customize the test runtime classpath for each container. First, let's setup the common compile-time dependencies in the main build file:
We then need to create a partial Gradle build file for each container that contains the container-specific dependencies and configuration. Let's start with Weld EE Embedded.
Create a file named weld-ee-embedded-profile.gradle and populate it with the following contents:
Here's the partial build file for Remote JBoss AS, named jbossas-remote-profile.gradle:
And finally the one for Embedded GlassFish, named glassfish-embedded-profile.gradle:
Now we need to import the appropriate partial Gradle build into the main build. The file will be selected based on the value of the project property named profile.
Tests are run in the Weld EE Embedded runtime using this command:
That's pretty much the same experience you get when you use Maven (and a whole heck of a lot simpler).
While the configuration is much simpler using the profiles strategy, there are two things to keep in mind:
- It crosses over into more than one build file
- You cannot run the tests in each container in a single build execution
If you have a better idea of how to integrate an Arquillian test suite into a Gradle build, we'd love to hear it on the Arquillian discussion forums.