Gradle: How to get output from test STDERR/STDOUT into console? - testing

(Gradle 3.2.1) I run some java tests, which logs output in Stderr/Stdout. I can see that output, if I start
gradle test --info
but in that case, much of unwanted output from 3-rd party libraries is there too.
Documentation suggests using logging.caputureStandardError / logging.caputureStandardError (loglevel), but it doesn't seem to have any effect.
tasks.withType(Test) {
logging.captureStandardOutput LogLevel.QUIET
logging.captureStandardError LogLevel.QUIET
}
Then if running gradle test, not STDERR/STDOUT is output in console.
How can I get just the output from the tests classes in console?

Add these lines to build.gradle :
apply plugin: 'java'
test {
dependsOn cleanTest
testLogging.showStandardStreams = true
}
Notice: dependsOn cleanTest is not necessary but if not used, you need to run cleanTest or clean task before test task.
Edit:
A better approach:
apply plugin: 'java'
test {
testLogging {
outputs.upToDateWhen {false}
showStandardStreams = true
}
}
Notice: outputs.upToDateWhen {false} is not necessary but if not used, you need to run cleanTest or clean task before test task.
For more info and options see the documentation.

For those using Kotlin/Kotlin DSL for Gradle, you need to put the following in your build.gradle.kts file:
tasks.withType<Test> {
this.testLogging {
this.showStandardStreams = true
}
}
Also as mentioned in another answer, you will need to run gradle clean test for the output to print every time.

The testLogging answer is correct. For me, since I already had a tasks.test section, I figured it'd be easier to put it there instead.
tasks.test {
useJUnitPlatform()
this.testLogging {
this.showStandardStreams = true
}
}

Extending on #Talha Malik solution's above (and the ones in this other post), when dealing with a multi-module android app the following can be used (root build.gradle)
// Call from root build.gradle
setupTestLogging()
fun Project.setupTestLogging() {
for (sub in subprojects) {
sub.tasks.withType<Test> {
testLogging {
exceptionFormat = TestExceptionFormat.FULL
}
}
}
}
(note that while exceptionFormat alone should be enough to get the wanted outcome, the events("standardOut" ...) mentioned above can be specified in the same way)

Related

Include dependency for custom sourceSet

I have a build.gradle.kts for a small, pure kotlin project (I am aware I am using slightly non-standard source paths):
plugins {
kotlin("jvm") version "1.3.72"
}
repositories { mavenCentral() }
dependencies {
implementation(kotlin("stdlib-jdk8"))
testImplementation("org.jetbrains.kotlin:kotlin-test")
testImplementation("org.jetbrains.kotlin:kotlin-test-junit")
}
sourceSets["main"].java.srcDir("src")
sourceSets["test"].java.srcDirs("test")
sourceSets {
create("demo")?.let {
it.java.srcDir("demo")
// Also tried: it.java.srcDirs("src", "demo")
it.compileClasspath += main.get().output
it.runtimeClasspath += main.get().output
}
}
tasks {
compileKotlin {
kotlinOptions.jvmTarget = "1.8"
}
compileTestKotlin {
kotlinOptions.jvmTarget = "1.8"
}
}
listOf("InteractiveClient", "LockingBufferDemo").forEach {
tasks.register<Jar>(it) {
manifest { attributes["Main-Class"] = "${it}Kt" }
from(sourceSets.main.get().output)
from(sourceSets["demo"].output) {
include("**/${it}Kt.class")
}
dependsOn(configurations.runtimeClasspath)
from({
configurations.runtimeClasspath.get().filter {
it.name.endsWith("jar") }.map { zipTree(it) }
})
}
}
When I try to run one of the "demo" sourceSet based jar tasks ("InteractiveClient" and "LockingBufferDemo"),1 I get a the long list of "Cannot access built-in..." errors indicating the kotlin stdlib is not properly in play.
The actual failing task is compileDemoKotlin, so I tried adding mimetically to the tasks block:
withType<org.jetbrains.kotlin.gradle.tasks.KotlinCompile> {
this.kotlinOptions.jvmTarget = "1.8"
}
Which makes no difference.
What's strange to me is that the demo stuff was originally in the test sourceSet, and changing the above back to that (by removing the definition, changing from(sourceSets["demo"]... to from(sourceSets.test... in the jar task(s), and moving the source file) makes the problem disappear. It works.
I don't want this stuff in with automated tests. I imagine I could put them in branches of the main or test set and then use a from() { exclude(... pattern in building the jars,
but that seems awkward and unnecessary.
How do I get a custom source set to compile against the default project dependencies?
See this other recent question of mine about the from(... include( in the jar tasks.
It looks to me like you are missing the configurations that will make the demo source sets use the same dependencies as the main set. Something like this:
configurations["demoImplementation"].extendsFrom(configurations.implementation.get())
configurations["demoRuntimeOnly"].extendsFrom(configurations.runtimeOnly.get())
There is an example in the user guide here that seems to have a very similar use case as yours.
Also, from the issue you created in the Gradle repository, you mentioned it failed with:
Unresolved reference: printlin
I am pretty sure this is a typo of println.
I'm not entirely sure what you're trying to do with your jar files, but I spotted a few problems in your build script:
You have set your source sets like this:
sourceSets["main"].java.srcDir("src")
sourceSets["test"].java.srcDirs("src", "test")
sourceSets {
create("demo")?.let {
it.java.srcDir("demo")
}
}
This means you're supposed the following directory structure:
- <module root>
- src <-- Belongs to both 'main' and a 'test' source sets!
- test <-- Belongs to the 'test' source set
- demo <-- Belongs to the 'demo' source set
As you can see, there's a directory that belongs to two source sets. I'm not sure how this turns out in practice, probably one or the other is discarded. Here's a more standard directory structure:
- <module root>
- src
- main
- test
- demo
You configure it like this:
sourceSets {
main {
java.srcDir("src/main")
}
test {
java.srcDir("src/test")
}
create("demo") {
java.srcDir("src/demo")
}
}
The task compileDemoKotlin actually exists, but you can't access it just like that. If you look at the compileKotlin and compileTestKotlin extension functions source, they look like this:
val TaskContainer.`compileKotlin`: TaskProvider<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>
get() = named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileKotlin")
So the trick is to use named to get the task instead:
named<org.jetbrains.kotlin.gradle.tasks.KotlinCompile>("compileDemoKotlin") {
kotlinOptions.jvmTarget = "1.8"
}
I don't know if that answers your question. If I missed anything please let me know.

Different lint-options per build type

I want to have different lint options per build-type.
I tried to simply add the options to the corresponding build types like this:
android {
buildTypes {
debug {
lintOptions {
textReport true
textOutput 'stdout'
warningsAsErrors false
abortOnError true
}
}
release {
lintOptions {
textReport true
textOutput 'stdout'
ignoreWarnings false
warningsAsErrors true
abortOnError true
}
}
}
but this does not work as expected:
e.g. in my project I have some lint warnings, but no errors. Thus I'd expect
./gradlew lintRelease
to fail, but
./gradlew lintDebug
to succeed (with warnings of course).
But this is not the case. With the config shown above, both builds fail.
The strange thing is, that it is dependent on the order: e.g. when I move the whole debug {} block after release {}, then both builds always succeed: so it seems that only the latest options are ever used...
What am I missing - or how to fix this?
I use gradle version 3.3
as a workaround we can use a gradle property which we can set to "debug"/"release": as explained here: Gradle plugin does not propagate debug/release to dependencies - Comment#91
e.g. in the gradle.properties file of the project define a variable:
myBuildType=debug
This will make sure that the default build type is "debug". You can override it via a gradle command line argument
./gradlew.bat -PmyBuildType=release ...
and in the build.gradle file of the project or subprojects:
warningsAsErrors rootProject.properties['myBuildType'] == 'release'
This answer may be helpful to you.
I solved the problem in a different way.
Add this task in your app build.gradle after the android { } block.
task setReleaseLintOptions {
doLast {
configure(android.lintOptions) {
// Put your specific lintOptions here
check 'ExtraTranslation', 'MissingTranslation', 'Untranslatable'
}
}
}
task setDebugLintOptions {
doLast {
configure(android.lintOptions) {
// Put your specific lintOptions here
check 'MissingDefaultResource', 'UnusedResources'
}
}
}
Then you can manually run these tasks before your lint tasks to configure the lint options before that run...
.gradlew setReleaseLintOptions lintRelease
.gradlew setDebugLintOptions lintDebug
This would run the options specified in our custom tasks for the lintRelease or lintDebug task.

intellij idea 14 and gradle issues when running integTests

I have a gradle project imported into idea 14.0.3. The integration tests run fine from the command line. They were also running without any problems in idea 13 from the context menu (running single tests). However, in 14, when I use the context menu in IDE, for some reason the tests that depend on class path resources from src/integTest/resources are failing due to resource not being found. Any idea how I can add this folder in the classpath search in Intellij 14? Has anyone seen this issue before?
If I move the same resource to src/test/resources (or src/main/resources), the tests run fine. So it seems like intellij is not simply looking under src/integTest/resources.
Appreciate the help!!
I have run into this before as well, add the following to your build.gradle file:
// work-around to fix IDE-run test failures (may be fixed in future Gradle versions)
task copyMainResourcesToTest(type: Copy) {
from "${projectDir}/src/main/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyMainResourcesToTest
task copyTestResourcesToTest(type: Copy) {
from "${projectDir}/src/test/resources"
into "${buildDir}/classes/test"
}
processTestResources.dependsOn copyTestResourcesToTest
I think this may be resolved in the newest release of Gradle but I have not verified yet. You will want to update the paths for your specific use case.
Looks like this is Bug (IDEA-128966) in IntelliJ 14.
The recommended workaround is something like this:
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/integTest/resources')
}
if(System.properties.'idea.active') {
main {
resources.srcDir file('src/integTest/resources')
}
}
}
For our projects I changed that to:
if(System.properties.'idea.active') {
test { //Add to test rather than main
That still works and I think it communicates the intent better.
This workaround assumes you have configured your integration tests like this in the build.gradle:
apply plugin: 'idea'
sourceSets {
integrationTest {
java.srcDir file('src/integTest/java')
resources.srcDir file('src/inteTest/resources')
}
}
configurations {
integrationTestCompile.extendsFrom testCompile
integrationTestRuntime.extendsFrom testRuntime
}
task integrationTest(type: Test, dependsOn: jar) {
testClassesDir = sourceSets.integrationTest.output.classesDir
classpath = sourceSets.integrationTest.runtimeClasspath
}
build.dependsOn(integrationTest)
Note: This answer was originally deleted by a moderator because of a duplicate answer that I posted on another question. I now deleted my answer there (and added a link to here) because I think it fits this question better.

How to get `gradlew idea` to get IDEA to use test conf for custom task?

I have the following:
sourceSets {
integrationTest {
java.srcDir file('.')
}
}
dependencies {
integrationTestCompile project(':sut-project')
}
task integrationTest(type: Test)
but when gradlew idea is run and the project opened, the Sources doesn't have a Tests conf for that project.
What needs to be done to get this to work?
The documentation for IDEA plugin is at http://www.gradle.org/docs/current/userguide/idea_plugin.html
From this links you can navigate to http://www.gradle.org/docs/current/dsl/org.gradle.plugins.ide.idea.model.IdeaModule.html where you can see how to map additional source roots (AKA content-roots in IntelliJ parlance) to your modules and configurations to classpath using proper scope. You will use something like:
idea {
module {
testSourceDirs += file('src/integTest/java')
scopes.TEST.plus += configurations.integrationTestCompile
}
}

Gradle Application Plugin : How can I run jvm application with -javaagent options?

I use application plugin in gradle (v1.10) to package and to run my apps.
So, now I need to use aspects (aspectj), and I dont want to use aspectj-compiler (ajc).
Is it possible to tweak gradle application run scripts, so my app could be run with load-time-weaving? Something like providing jvm options:
-javaagent:_path_to_aspectj_weaver.jar
Yep, that's done like this:
project(':whatever') {
apply plugin: 'application'
mainClassName = 'some.Main'
repositories { mavenCentral() }
dependencies {
// substitute needed version of aspectj
runtime "org.aspectj:aspectjweaver:$aspectj"
}
applicationDefaultJvmArgs = [
"-javaagent:\$APP_HOME/lib/aspectjweaver-${aspectj}.jar"
]
// $ symbol gets escaped in script anyway:( so we need to replace it.
startScripts {
doLast {
unixScript.text = unixScript.text.replace('\\$APP_HOME', '\$APP_HOME')
// do something like this for Windows scripts also
}
}
}