Integration tests in Gradle using Maven's naming conventions? - java

Coming from Maven, I'm exploring Gradle as an alternative. Technologies: Java 11, jUnit 5, Maven 3.6, Gradle 5.6.
I'm stuck in configuring the integration tests. Following the default naming conventions of Maven's Surefire and Failsafe plugins, my tests live in the standard test directory and are distinguished by their suffix: unit tests end in Test.java and integration tests end in IT.java.
Is it possible to have the same setup in Gradle? So far I've seen two ways:
use jUnit5's tags (which means I would have to go and tag every integration test)
use separate directories for unit and integration tests
Ideally, I'd like to keep my folder structure as-is, because it affects multiple git repositories.

Okay, I think I managed to get it working with source sets, thanks to the feedback of Lukas and Slaw.
Please let me know if this can be improved:
// define the dependencies of integrationTest, inherit from the unit test dependencies
configurations {
integrationTestImplementation.extendsFrom(testImplementation)
integrationTestRuntimeOnly.extendsFrom(testRuntimeOnly)
}
sourceSets {
test {
java {
// exclude integration tests from the default test source set
exclude "**/*IT.java"
}
}
// new source set for integration tests
integrationTest {
// uses the main application code
compileClasspath += sourceSets.main.output
runtimeClasspath += sourceSets.main.output
java {
// the tests are at the same directory (or directories) as the unit tests
srcDirs = sourceSets.test.java.srcDirs
// exclude the unit tests from the integration tests source set
exclude "**/*Test.java"
}
resources {
// same resources directory (or directories) with the unit tests
srcDirs = sourceSets.test.resources.srcDirs
}
}
}
// define the task for integration tests
task integrationTest(type: Test) {
description = "Runs integration tests."
group = "verification"
testClassesDirs = sourceSets.integrationTest.output.classesDirs
classpath = sourceSets.integrationTest.runtimeClasspath
shouldRunAfter test
// I'm using jUnit 5
useJUnitPlatform()
}
// make the check task depend on the integration tests
check.dependsOn integrationTest

Related

Gradle: build test classes even when tests are not executed

I have created an integration test task for my java project following this guide.
Omitting some irrelevant details, the task is like follows:
apply plugin: 'java'
task integrationTests (type: Test){
testClassesDir = sourcesets.integrationTests.outputClasesDir
classpath = sourceSets.IntegrationTests.runtimeClasspath
}
sourceSets {
integration {
java {
//integration test sources
}
}
configurations {
integrationTestsCompile.extendsFrom. testCompile
integrationTestsRuntime.extendsFrom testRuntime
}
check.dependsOn integrationTests
This works perfectly except that now I need to split the test in two stages: unit tests in the build machines and integration tests in integration test machines (because they need some setup)
To make thinks more complicated, I cannot recompile code in the integration test machines, so I need to compile, but not executed integration test code in the build machines.
How can I do this? I've seen there's an integrationTestsClasses task that does the compilation, but I would like to call it automatically when building the project.
Thanks in advance

Running tests from JAR dependency

I'm working on creating a JAR with my test code and planning to run the test from a different project.
Below is the approach I'm trying to implement.
Project B:
configurations { testApi }
task testJar ....
artifacts { testApi testJar }
Project A:
dependencies {
testRuntime "xx.xxx.xxx.projectName", configuration: "integtest";
}
The test seems to be not running with this approach. Any idea on what could be the issue? Any better approaches?
Gradle only looks for test classes in the directories configured via testClassesDirs property of the respective Test-type task which with the java plugin is project.sourceSets.test.output.classesDirs for the test task. Running tests from JAR files in dependencies is not supported.
You need to extract the JAR file and add the extracted directory to this property. I think something like the following construct should work, I didn't test it though:
configurations {
externalTests
}
dependencies {
externalTests "xx.xxx.xxx.projectName", configuration: "integtest"
testRuntime "xx.xxx.xxx.projectName", configuration: "integtest"
}
test {
// if only one dependency in externalTests you can use the simpler, it will fail if there are multiple dependencies
testClassesDirs += zipTree(configurations.externalTests.singleFile)
// if multiple dependencies in externalTests you need to use
testClassesDirs += configurations.externalTests.files.collect { zipTree it }.sum()
}

Exclude tests using J2ObjC Gradle Plugin

Is it somehow possible to exclude test classes from java-to-ObjcC conversion with j2objc-gradle plugin?
The J2ObjC Gradle Plugin can exclude files from both translation and tests. It uses Ant style exclude / include pattern matching on filenames. This is is described in the Gradle documentation with examples and the PatternFilterable class.
As a simple example:
j2objcConfig {
...
testPattern {
// Only run Java unit tests that end with "Test.java"
include '**/*Test.java'
// Exclude a single test without needing to specify the full path
exclude '**/LogTest.java'
// Exclude all tests within "ignoreDirectory"
exclude 'ignoreDirectory/**'
}
...
}

Gradle equivalent of Surefire classpathDependencyExclude

I'm trying to migrate java project from maven to gradle. The problem is very tricky classpath dependency configuration for tests now.
Our maven-surefire-plugin configuration:
<includes>
<include>**/SomeTest1.java</include>
</includes>
<classpathDependencyExcludes>
<classpathDependencyExclude>com.sun.jersey:jersey-core</classpathDependencyExclude>
</classpathDependencyExcludes>
There are different classpathes for different test-classes. How can I implement it with Gradle?
First of all you need to differ your tests sources into separate sourceSets. Say, we need to run tests from package org.foo.test.rest with a little different runtime classpath, than other tests. Thus, its execution will go to otherTest, where remain tests are in test:
sourceSets {
otherTest {
java {
srcDir 'src/test/java'
include 'org/foo/test/rest/**'
}
resources {
srcDir 'src/test/java'
}
}
test {
java {
srcDir 'src/test/java'
exclude 'org/foo/rest/test/**'
}
resources {
srcDir 'src/test/java'
}
}
}
After that, you should make sure that otherTest has all required compile and runtime classpaths set correctly:
otherTestCompile sourceSets.main.output
otherTestCompile configurations.testCompile
otherTestCompile sourceSets.test.output
otherTestRuntime configurations.testRuntime + configurations.testCompile
The last thing is to exclude (or include) unneeded runtime bundles from test:
configurations {
testRuntime {
exclude group: 'org.conflicting.library'
}
}
And to create Test Gradle task for otherTest:
task otherTest(type: Test) {
testClassesDir = sourceSets.otherTest.output.classesDir
classpath += sourceSets.otherTest.runtimeClasspath
}
check.dependsOn otherTest
Use next workaround:
Create source set for needed tests
Add configurations for created sourceSet
Add task for run test with custom configuration
Configure test task dependOn customized test task
Configure Report plugin for generate beautiful html report :)
Like this getting started

How to run JUnit tests with Gradle?

Currently I have the following build.gradle file:
apply plugin: 'java'
sourceSets {
main {
java {
srcDir 'src/model'
}
}
}
dependencies {
compile files('libs/mnist-tools.jar', 'libs/gson-2.2.4.jar')
runtime fileTree(dir: 'libs', include: '*.jar')
}
This build.gradle file is for my repository here. All of my main files are in src/model/ and their respective tests are in test/model.
How do I add a JUnit 4 dependency correctly and then run those tests in the folders of tests/model?
How do I add a junit 4 dependency correctly?
Assuming you're resolving against a standard Maven (or equivalent) repo:
dependencies {
...
testCompile "junit:junit:4.11" // Or whatever version
}
Run those tests in the folders of tests/model?
You define your test source set the same way:
sourceSets {
...
test {
java {
srcDirs = ["test/model"] // Note #Peter's comment below
}
}
}
Then invoke the tests as:
./gradlew test
EDIT: If you are using JUnit 5 instead, there are more steps to complete, you should follow this tutorial.
If you set up your project with the default gradle package structure, i.e.:
src/main/java
src/main/resources
src/test/java
src/test/resources
then you won't need to modify sourceSets to run your tests. Gradle will figure out that your test classes and resources are in src/test. You can then run as Oliver says above. One thing to note: Be careful when setting property files and running your test classes with both gradle and you IDE. I use Eclipse, and when running JUnit from it, Eclipse chooses one classpath (the bin directory) whereas gradle chooses another (the build directory). This can lead to confusion if you edit a resource file, and don't see your change reflected at test runtime.
If you created your project with Spring Initializr, everything should be configured correctly and all you need to do is run...
./gradlew clean test --info
Use --info if you want to see test output.
Use clean if you want to re-run tests that have already passed since the last change.
Dependencies required in build.gradle for testing in Spring Boot...
dependencies {
compile('org.springframework.boot:spring-boot-starter')
testCompile('org.springframework.boot:spring-boot-starter-test')
}
For some reason the test runner doesn't tell you this, but it produces an HTML report in build/reports/tests/test/index.html.
This is for Kotlin DSL (build.gradle.kts) and using JUnit 5 (JUnit platform):
tasks.test {
// Discover and execute JUnit4-based tests
useJUnit()
// Discover and execute TestNG-based tests
useTestNG()
// Discover and execute JUnit Platform-based (JUnit 5, JUnit Jupiter) tests
// Note that JUnit 5 has the ability to execute JUnit 4 tests as well
useJUnitPlatform()
}
dependencies {
testImplementation("org.junit.jupiter:junit-jupiter:5.8.2")
// ...
}
testCompile is deprecated. Gradle 7 compatible:
dependencies {
...
testImplementation 'junit:junit:4.13'
}
and if you use the default folder structure (src/test/java/...) the test section is simply:
test {
useJUnit()
}
Finally:
gradlew clean test
Alos see: https://docs.gradle.org/current/userguide/java_testing.html
If you want to add a sourceSet for testing in addition to all the existing ones, within a module regardless of the active flavor:
sourceSets {
test {
java.srcDirs += [
'src/customDir/test/kotlin'
]
print(java.srcDirs) // Clean
}
}
Pay attention to the operator += and if you want to run integration tests change test to androidTest.
GL

Categories