Run gradle static analysis plugins bug exclude unit tests - java

I am using some static analysis plugins (spotbugs, pmd) attached to my gradle build. They run automatically when you run gradlew check or something that depends on check.
I am trying to find a way to run JUST the parts of check, but exclude unit tests, in a command. Since check depends on test, I am not sure how to do this, if it's possible.
I have a large number of java / android modules and it takes a long time to do a full build with tests and static analysis, so I want to break them up as separate tasks on separate CI systems.

You should be able to do:
./gradlew check --exclude-task test
See the docs here

Instead of calling the task check with excluded task test as proposed by Dave, you can simply create a new task and add dependencies on all tasks that perform static analysis:
task staticAnalysis {
dependsOn 'spotbugsMain'
dependsOn 'pmdMain'
}
You may then call ./gradle staticAnalysis.

Related

In a java maven or gradle project, can we write test cases in main package rather than in test package?

How do we make mvn build or Gradle build to take test cases from the main package if we have written test cases in the main package?
In gradle you just redefine the main and test sourceSets with filters in your build.gradle file to exclude / include the test files in the specific phase of the build.
For example the file named LibraryTest.java will be compiled and executed only during the test phase.
sourceSets {
main {
java {
srcDirs = ['src/main/java']
exclude '**/*Test.java'
}
}
test {
java {
srcDirs = ["src/main/java"]
include '**/*Test.java'
}
}
}
you can write your test cases where ever you want, BUT!
It is not a recommended practice, so if you are using maven/gradle - they will give you dedicated folder/path for writing test cases.
The reason why it is not recommended - is maven/gradle provides lot of plugins which will help you to run your test cases, generate reports for those test cases, control the build if test cases fails.
All these plugins will look up at the default path, so if you decide to use a different path rather than default - you need to change the path for test cases in all your plugin.
so if you choose to use your own path for test resources, you are just adding overhead of additional configuration changes.

run checkstyles in subprojects before all tests in all subprojects

I have gradle project with 4 subprojects. I have current root gradle.build with checkstyle:
allprojects {
apply plugin: "checkstyle"
checkstyle {
...
}
}
so when I run ./gradlew build in the main folder, I get next:
checkstyle for 1st subproject, then tests. Then it runs checkstyle for 2nd subproject and then tests for 2nd, etc.
The problem is: if I have long tests in 1st subproject, I can wait a lot of time, and then discover that I have 2 spaces in the 4th project, so checkstyle fails, but I was waiting so much time for it.
What I really want:
run all checks (checkstyle, and I have pmd too) for all subprojects, and then run all tests in all subprojects. It will save a lot of time for everybody in the team.
Can I do it except, make 2 different pipelines, and run them separately? like: ./gradlew allMyCheckstyles && ./gradlew build.
I would love to use just ./gradlew build
Thanks!
I tried many dependsOn, runAfter, but it didn't work out.
Apologies, a previous version of this answer misinterpreted the requirements of this question.
Here's a solution that should do what you want:
// Create a lifecycle task in the root project.
// We'll make this depend on all checkstyle tasks from subprojects (see below)
def checkstyleAllTask = task("checkstyleAll")
// Make 'check' task depend on our new lifecycle task
check.dependsOn(checkstyleAllTask)
allProjects {
// Ensure all checkstyle tasks are a dependency of the "checkstyleAll" task
checkstyleAllTask.dependsOn(tasks.withType(Checkstyle))
tasks.withType(Test) {
// Indicate that testing tasks should run after the "checkstyleAll" task
shouldRunAfter(checkstyleAllTask)
// Indicate that testing tasks should run after any checksytle tasks.
// This is useful for when you only want to run an individual
// subproject's checks (e.g. ./gradlew ::subprojA::check)
shouldRunAfter(tasks.withType(Checkstyle))
}
}
Documentation here and here

Jenkins how to force tasks to run even with failure in one of them?

Hi I'm running some tasks using Jenkins. There I have 5 tasks to run sequentially like:
test --tests apptest.WP_RecuperarSenha.testTeste_recuperar_senha_e_logar
test --tests apptest.WP_CadastroInvalido.testTeste_cadastro_campos_invalidos
test --tests apptest.WP_CadastroEmBranco.testedecadastrobranco
test --tests apptest.WP_InteracaoProduto.testeinteracaoproduto
I would like to know how to force Jenkins to keep running the build even, for example, if test --tests apptest.WP_RecuperarSenha.testTeste_recuperar_senha_e_logar fails. How to keep running it?
If you're using a free-style job you can use the conditional step plugin for each task and set each of the steps to always run.
If you utilize the pipeline plugin you can surround each task in a try/catch block and then inside the catch write currentBuild.result = 'FAILURE' (or currentBuild.result = 'UNSTABLE' if it's more meaningful to you).

JUnit tests influence each other

I'm working with a lot of legacy code. There was a JUnit-TestSuite to begin with. When running all tests with gradle, they failed. When running the test in IntelliJ, they worked. We configured gradle to use the test suite.
Now someone reported tests working locally without gradle, but not with gradle. It's time we fix this mess.
Is there a smart way to figure out which test leaves some configuration behind or which tests relies on the other tests?
The most likely cause of this "bleed" from one test into another is mutable static values. By default, all tests are run by the same JVM so a static variable which is "mutated" by one test will be "dirty" in another test.
Mutable statics are evil! I'm working on a codebase currently with mutable statics everywhere and it's a mess. If possible you should refactor to use dependency injection and store mutable state in instances and not statics.
The best workaround is to find the tests which "dirty" the static mutable variables and do
#After
public void cleanup() {
SomeStatic.reset();
}
If you can't find the "dirty" test which is causing the issue, you might be forced to do the following in the "failing" test. This is not preferred, and a little hacky
#Before
public void cleanBefore() {
SomeStatic.reset();
}
But this has a slight code "smell". Better to find the offending test which "dirties" the mutable static
The "nuclear" option is to run each test in its own jvm. This is a total hack and should be avoided at all costs. It will drastically increase the time it takes to run your tests
test {
forkEvery = 1
}
See Test.forkEvery
I recently diagnosed a similar issue in a Gradle Java project, where a test was working when run individually, but not when run as part of the Gradle build.
In order to track down the offending test that was breaking the subsequent test, I first configured Gradle to print out the tests that were run using beforeTest, so I could tell what all was running prior to my test:
test {
beforeTest { TestDescriptor descriptor ->
logger.lifecycle("$descriptor.className#$descriptor.name")
}
}
This printed the tests in the order in which they ran:
$./gradlew test
> Task :test
com.example.Test1#firstTest()
com.example.Test1#secondTest()
com.example.Test2#firstTest()
com.example.Test2#secondTest()
com.example.Test3#firstTest()
com.example.Test3#secondTest()
com.example.BrokenTest#brokenTest()
BrokenTest > brokenTest() FAILED
java.lang.AssertionError at BrokenTest.java:34
com.example.Test4#firstTest()
com.example.Test4#secondTest()
Now that I knew which test classes were running before the broken test, I knew that one (or more) of those tests were causing the test to break.
Next, I added test filtering in my Gradle build to only run those tests that ran before the broken test, plus the broken test itself:
test {
filter {
includeTestsMatching 'com.example.Test1'
includeTestsMatching 'com.example.Test2'
includeTestsMatching 'com.example.Test3'
includeTestsMatching 'com.example.BrokenTest'
}
}
After doing a sanity check Gradle build to confirm that the test was still broken, I commented out groups of tests and reran the build until I was able to narrow it down to the test that caused the build to break:
test {
filter {
// includeTestsMatching 'com.example.Test1'
includeTestsMatching 'com.example.Test2'
// includeTestsMatching 'com.example.Test3'
includeTestsMatching 'com.example.BrokenTest'
}
}
In this example, the build broke when Test2 was run before BrokenTest, but not when Test1 or Test3 were. Armed with this information, I could dive deeper into what specifically about Test2 was affecting the system in such a way as to break the other test when it was run after it.

Gradle: Multi-project dependency: Tasks of the same name executing together

I have a multi-project dependency in my gradle build, but there's a feature that's somewhat in my way. Whenever I call a task name that exists in both projects, it calls them both. I don't like that.
My directory structure is as follows:
[Root]
---->[projA]
----------->build.gradle
---->[projB]
----------->build.gradle
So I have projB dependent on projA in my code.
Say I have a task run in projB:
task run << {
println 'projB running'
}
And I also have a task run in projA:
task run << {
println 'projA running'
}
By calling gradle run, I would get
:run
projB running
:projA:run
projA running
Is there any way to prevent some of the tasks from having this dependency? Some of them, say clean is fine, but I'd prefer to have specific tasks separate (without having to change the naming scheme).
The equivalent of what I want can be achieved by doing either:
gradle run -x :projA:run
or
gradle :run
I want a solution that is within the build file, though.
Thanks!
That fact that projB declares a project dependency on projA is irrelevant for the behavior you are seeing. If you execute a task from the root project of a multi-project build Gradle will try to find the task in any of its subprojects with the requested name and execute it. This feature is called task execution matching. Given this default behavior there's no way Gradle could know which run task you mean when executing gradle run from the root project. I'd suggest you define what you want to execute on the command line as mentioned in my previous comment.
If you really wanted to add logic to your build script, then you could achieve it with the following code:
def taskRequests = gradle.startParameter.taskRequests
def runTaskRequest = taskRequests.find { it.args.contains('run') }
if (runTaskRequest) {
gradle.startParameter.excludedTaskNames = [':projA:run']
}
The code provided would prevent the execution of the run task for the subproject projA if you execute the command gradle run. Keep in mind that it would also exclude :projA:run if you navigate to the projA subdirectory and run the same command. If you still want to be able to execute the run task from the subdirectory, then you'll have to build in additional logic.

Categories