I've defined my sourceSets as
sourceSets {
// Configuring SourceSets for all connector source files.
main {
java {
srcDirs = ['src']
}
}
test {
// integrationTests
}
unitTests {
//unitTests
}
}
test {
// integrationTests
}
task('unitTest', type: Test) {
//unitTests
}
When I kick off ./gradlew build it's check task basically calls the test target.
Can I override the default gradle build tasks's 'check' mechanism to call unitTest here instead of test?
First of all, please consider just using the task test for unit tests and using another source set for integration tests. Gradle and its plugins follow an approach called convention over configuration and the convention of the Java plugin is to use the task test for unit tests.
To actually answer your question, you can access and modify the dependencies of each task using getDependsOn() and setDependsOn(Iterable<?>), so a simple solution to your problem could be the following code:
check {
dependsOn.clear()
dependsOn unitTest
}
This removes all task dependencies from the task check and then adds a dependency on the task unitTest. However, this may cause new problems, because other plugins may automatically register task dependencies for check that will be removed, too.
An obvious improvement to the code above would be to just remove the dependency on the test task instead of all task dependencies. Sadly, this is not as simple as one would think. You may have noticed that the method getDependsOn() returns a Set<Object> and not a Set<Task>. For convenience, task dependencies may be expressed not only using tasks but also by passing other objects that will resolve to tasks later on (e.g. a string containing the name of a task). The current version of the Java plugin uses a Provider<Task> to register the dependency between the task check and the task test. To just remove the dependency on the task test, you would need to iterate over all dependencies in dependsOn and find the one with the type Provider that returns the task test via its get() method. You could then remove that Provider from dependsOn.
As you can see, it is possible to remove task dependencies once they have been registered, but it is not that easy, so you should probably just follow the convention and use the task test for unit tests.
Related
What I would like to achieve
I would like to have a manual gradle task that I can generate Java classes based on Json schema. However, I don't want this task to run when I run other fx. gradle build.
What I did
Firstly I've create simple gradle java project with
gradle init
Then I have added jsonschema2dataclass plugin and configure it as follows (my current build.gradle):
/*
* This file was generated by the Gradle 'init' task.
* (...)
*/
plugins {
// Apply the application plugin to add support for building a CLI application in Java.
id 'application'
id "org.jsonschema2dataclass" version "4.5.0"
}
repositories {
// Use Maven Central for resolving dependencies.
mavenCentral()
}
dependencies {
// Use JUnit Jupiter API for testing.
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.6.2'
// Use JUnit Jupiter Engine for testing.
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine'
// This dependency is used by the application.
implementation 'com.google.guava:guava:29.0-jre'
}
application {
// Define the main class for the application.
mainClass = 'GradlePlayground.App'
}
jsonSchema2Pojo {
includeGeneratedAnnotation = true
generateBuilders = true
targetPackage = 'org.example.api' // specify package for your needs
targetDirectoryPrefix = file("${project.rootDir}/app/src/main/java")
source.setFrom files("${project.rootDir}/app/src/main/resources/json")
}
What I've tried
Add task.enabled = false
Put plugin configuration into another task
Check source code of plugin to find a way to disconnect this task from build task
But all above trails have failed. When I run gradle tasks I can always see generateJsonSchema2DataClass and generateJsonSchema2DataClass0 as part of build tasks.
I'm using java 8 and gradle 6.9.3
I'm the author of the gradle plugin.
Short answer for your question is "no, it's not an intended flow for a normal project". However, it's always possible to create a new project, build it once and extract the sources.
Could you please explain, what the reason you want to exclude run from the build chain?
My only guess is to build and publish models. And if this is a case, it's possible to do this using some gradle magic, which described in discussions in the GitHub project
UPD: Based on your gradle script, I have a lot of "why" questions I'd like to ask, it'll be easier if you
I have several jars with test classes in the private Maven repository. As shown below, these jars are imported by a customized configuration testJar.
dependencies {
testJar "com.example:test1:1.0"
testJar "com.example:test2:1.0"
}
I want to run these tests in separate Gradle test tasks. i.e.
Execute tests in test-1.jar with task test1.
Execute tests in test-2.jar with task test2.
Why not execute these tests in the same task?
The tests in different jars may affect each other.
To achieve this, I should register tasks test1 and test2 after the configuration testJar is resolved.
You can create additional Gradle test tasks named test*, and use the include and exclude properties to configure which task runs what subset of tests. The jar has absolutely nothing to do with running tests, because Gradle doesn’t know what tests are in it. The tests are discovered at runtime by the appropriate test engine (like JUnit 5).
What is a simple (but modern best-practices) way to configure Gradle so that it allows me to run integration tests similar to how a default Maven Failsafe configuration would work? I've read the Gradle docs for tests—in particular the Gradle docs for integration tests—but they seem pretty complicated (in comparison with Maven Failsafe), and moreover I don't believe the examples work in the same way.
What I'm looking for is pretty straightforward:
There would be some separate task—let's call it integrationTest for the sake of discussion.
The integrationTest task would not run when I invoke gradle test.
The integrationTest task would run (after the test task) when I invoke gradle integrationTest.
The integrationTest task would run (after the test task) when I invoke gradle check.
The integrationTest task would have identical dependencies and classpath configurations as the test task.
The integrationTest task would use the same source path (i.e. src/test/java) as the test task, but would only run tests ending in *IT (just to simplify the default Failsafe inclusion pattern for this discussion).
The test task would ignore all tests ending in *IT.
That's actually a pretty simple use case. (I just went into details so there would be no ambiguity.) I can turn that on in Failsafe using two lines to indicate goals, and three lines to indicate a dependency. Since Gradle takes the XML verbosity out of the equation, I should be able to configure that in two lines, right?
Just to be clear, I don't want to use Maven Failsafe in Gradle. I just want to configure Gradle to behave in a similar way as the default Failsafe configuration, as I detailed above.
in particular the Gradle docs for integration tests—but they seem pretty complicated (in comparison with Maven Failsafe)
You're comparing a plugin (Maven Failsafe) to standard/vanilla Gradle configuration. A plugin abstracts away all the underlying details so it's not fair to compare the two. If you look at the source of Maven Failsafe, you'll see it is equally 'complicated' compared to Gradle.
(...) and moreover I don't believe the examples work in the same way.
The docs for configuring integration test work for typical applications. However since you have specific needs, so you'll need to adapt them.
Since Gradle takes the XML verbosity out of the equation, I should be able to configure that in two lines, right?
No because again, you're comparing a plugin to standard/vanilla Gradle configuration. XML vs Groovy/Kotlin DSL is up for debate which is better or worse and is a matter of opinion.
For your requirements, I believe I've captured them below (untested):
sourceSets {
create("integrationTest") {
compileClasspath += sourceSets.test.get().output
runtimeClasspath += sourceSets.test.get().output
}
}
val integrationTestImplementation by configurations.getting {
extendsFrom(configurations.testImplementation.get())
}
configurations["integrationTestRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())
val integrationTest by tasks.registering(Test::class) {
description = "Runs integration tests."
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
filter {
includeTestsMatching("IT*")
includeTestsMatching("*IT")
includeTestsMatching("*ITCase")
}
shouldRunAfter("test")
}
tasks {
test {
filter {
excludeTestsMatching("IT*")
excludeTestsMatching("*IT")
excludeTestsMatching("*ITCase")
}
}
register("integrationTest", Test::class) {
description = "Runs integration tests."
group = "verification"
testClassesDirs = sourceSets["integrationTest"].output.classesDirs
classpath = sourceSets["integrationTest"].runtimeClasspath
filter {
includeTestsMatching("IT*")
includeTestsMatching("*IT")
includeTestsMatching("*ITCase")
}
shouldRunAfter(test)
}
}
Although this is a bit verbose/awkward since you want integration tests to be within the same source set as test. So the above can be simplified to just:
tasks {
test {
filter {
excludeTestsMatching("IT*")
excludeTestsMatching("*IT")
excludeTestsMatching("*ITCase")
}
}
register("integrationTest", Test::class) {
description = "Runs integration tests."
group = "verification"
testClassesDirs = sourceSets.test.get().output.classesDirs
classpath = sourceSets.test.get().runtimeClasspath
filter {
includeTestsMatching("IT*")
includeTestsMatching("*IT")
includeTestsMatching("*ITCase")
}
shouldRunAfter(test)
}
}
Say, I have a hierarchy of Gradle projects and some of them have java plugin applied:
root
projA
projA1
projA2 (java)
projB
projB1 (java)
projB2
projB21 (java)
projB22 (java)
projC (java)
I want to execute the test task in all subprojects where this task exists: :projA:projA2:test, :projB:projB1:test and :projC:test. Probably I will add more projects in future and I don't want to manually support a list of all test tasks in all subprojects. How can I achieve it?
One thing that came to my mind is something like the following:
// In root I iterate over all subprojects and find the task by name causing
// its creation and configuration
tasks.register("testAll") {
dependsOn subprojects.findResults { it.tasks.findByName("test") }
}
I don't like this approach as it goes against task configuration avoidance style.
Another option is to iterate over subprojects and check if the java plugin is applied there:
// In root
tasks.register("testAll") {
dependsOn subprojects.findAll { it.plugins.hasPlugin("java") }.collect { it.tasks.named("test") }
}
It works but I have a filling that I miss something simpler...
EDIT 1: Sorry for that but I forgot one important detail - I need to run tests in a subtree of projects. Say, everything down the path :projB.
Unless I'm missing something, you want to run tests for all of your submodules.
You can just...do that.
./gradlew clean test
This will run the test task in all of the subprojects that have it sufficiently configured.
If you need to run the tasks in a specific subproject, from the root project you can specify the subproject you want to run the task.
./gradlew clean :projB:test
If your subprojects have a task that needs to run after test, then you can do this in your subprojects block.
subprojects {
myTask.dependsOn("test")
}
As a part of a TDD workflow, I want to be able to check if my Java codebase compiles, but not if the tests pass.
Currently, if I run gradle build it runs the compile tasks (for source and tests) and then also executes the test task (and returns a non-zero exit code since the tests fail).
So I find that I have to run gradle build -x test to exclude the test task, and get a successful zero exit code.
What do I add to my build.gradle to define a new task, say compile that is an alias for build x test?
So far I have this, but it doesn't seem like dependsOn takes any arguments to customize the build task I want to execute:
task compile {
dependsOn build
}
I've been reading the docs here, I see different kinds of dependency chaining mechanisms, but not to disable/exclude a particular task. How does the -x flag even work then? I assumed there would be a way to control it programmatically too.
Thanks to Bjørn Vester's answer and reading the docs, I have implemented my task as follows:
task compile {
dependsOn classes
dependsOn testClasses
}
There are lots of different tasks you can run individually. For instance:
gradle classes: Will compile your "main" code.
gradle testClasses: Will compile your "main" code as well as test code.
gradle jar: Will compile your "main" code and assemble it into a jar.
None of the above will run your unit tests. On the other hand, the build task depends on all of the above, as well as the test task and more.
In general, if you like to run a particular set of tasks, you do that by defining a new task and then make dependencies to those other tasks you like to run with it. You tried that already, but instead of build you should have used something like compileJava or classes whatever other tasks you need. But always check if there isn't one already that satisfies your needs, like there are in this case. You can read about what tasks are available in Java projects in the documentation for the Gradle java plugin.