How do I show a list of all the test failures after completion of a gradle task involving tests - testing

After running gradle tasks that include tests on my multi-module project, I want to see a summary of every test failure across all modules, e.g.
module 1:
testmodule1thing1 PASSED
testmodule1thing2 FAILED
results
2 tests 1 passed 1 failed
module 2:
testmodule2thing1 PASSED
testmodule2thing2 FAILED
results
2 tests 1 passed 1 failed
module 3:
testmodule3thing1 FAILED
results
1 tests 1 passed 1 failed
BUILD FAILED
========= I already have everything above this line
test failures:
testmodule1thing1
testmodule2thing2
testmodule3thing1
========= I want everything between the last line and this line
Is this possible? If so, how? If a full task summary isn't possible, I can live with a per-module summary

This can also be accomplished directly within the test task itself:
tasks.withType(Test) {
// a collection to track failedTests
ext.failedTests = []
afterTest { descriptor, result ->
if (result.resultType == TestResult.ResultType.FAILURE) {
String failedTest = "${descriptor.className}::${descriptor.name}"
logger.debug("Adding " + failedTest + " to failedTests...")
failedTests << [failedTest]
}
}
afterSuite { suite, result ->
if (!suite.parent) { // will match the outermost suite
// logs each failed test
if (!failedTests.empty) {
logger.lifecycle("Failed tests:")
failedTests.each { failedTest ->
logger.lifecycle("${failedTest}")
}
}
}
}
}

You can use a testlistener in combination with the buildFinished hook for that. A very simple solution can look like this first draft:
allprojects {
// add a collection to track failedTests
ext.failedTests = []
// add a testlistener to all tasks of type Test
tasks.withType(Test) {
afterTest { TestDescriptor descriptor, TestResult result ->
if(result.resultType == org.gradle.api.tasks.testing.TestResult.ResultType.FAILURE){
failedTests << ["${descriptor.className}::${descriptor.name}"]
}
}
}
// print out tracked failed tests when the build has finished
gradle.buildFinished {
if(!failedTests.empty){
println "Failed tests for ${project.name}:"
failedTests.each { failedTest ->
println failedTest
}
println ""
}
}
}
Another option to have better visibility for your failed tests is maybe using gradle build scans (https://plugins.gradle.org/plugin/com.gradle.build-scan).

Related

Gatling feeder/parameter issue - Exception in thread "main" java.lang.UnsupportedOperationException

I just involved the new project for API test for our service by using Gatling. At this point, I want to search query, below is the code:
def chnSendToRender(testData: FeederBuilderBase[String]): ChainBuilder = {
feed(testData)
exec(api.AdvanceSearch.searchAsset(s"{\"all\":[{\"all:aggregate:text\":{\"contains\":\"#{edlAssetId}_Rendered\"}}]}", "#{authToken}")
.check(status.is(200).saveAs("searchStatus"))
.check(jsonPath("$..asset:id").findAll.optional.saveAs("renderedAssetList"))
)
.doIf(session => session("searchStatus").as[Int] == 200) {
exec { session =>
printConsoleLog("Rendered Asset ID List: " + session("renderedAssetList").as[String], "INFO")
session
}
}
}
I declared the feeder already in the simulation scala file:
class GVRERenderEditor_new extends Simulation {
private val edlToRender = csv("data/render/edl_asset_ids.csv").queue
private val chnPostRender = components.notifications.notice.JobsPolling_new.chnSendToRender(edlToRender)
private val scnSendEDLForRender = scenario("Search Post Render")
.exitBlockOnFail(exec(preSimAuth))
.exec(chnPostRender)
setUp(
scnSendEDLForRender.inject(atOnceUsers(1)).protocols(httpProtocol)
)
.maxDuration(sessionDuration.seconds)
.assertions(global.successfulRequests.percent.is(100))
}
But Gatling test failed to run, showing this error: Exception in thread "main" java.lang.UnsupportedOperationException: There were no requests sent during the simulation, reports won't be generated
If I hardcode the #{edlAssetId} (put the real edlAssetId in that query), I will get result. I think I passed the parameter wrongly in this case. I've tried to print the output in console log but no luck. What's wrong with this code? I would appreciate your help. Thanks!
feed(testData)
exec(api.AdvanceSearch.searchAsset(s"{\"all\":[{\"all:aggregate:text\":{\"contains\":\"#{edlAssetId}_Rendered\"}}]}", "#{authToken}")
.check(status.is(200).saveAs("searchStatus"))
.check(jsonPath("$..asset:id").findAll.optional.saveAs("renderedAssetList"))
)
You're missing a . (dot) before the exec to attach it to the feed.
As a result, your method is returning the last instruction, ie the exec only.

IntelliJ check problem during Hyperskill Kotlin learning

I'm working on a Jetbrains Hyperskill track KOTLIN, it's my third project and I never had this kind of problem.
I found this post (here), and tried their suggestions (Which are the same that JetBrains give on their wiki/FAQ), but didn't work.
The project is:
Unit Converter (Heavy Duty Step 4/5)
Here is my code:
package converter
fun main() {
loopcheck# while (true) {
var conversion: Double
print("Enter what you want to convert (or exit): ")
val userInput = readln()
if (userInput == "exit") break#loopcheck
val (originalNumber, originalUnit, convertedUnit) = userInputSplit(userInput)
// Validating inputs/Enums + exception checks
if (originalNumber == null) {
println("Wrong number")
continue#loopcheck
}
if (originalUnit == null && convertedUnit != null) {
println("Conversion from ??? to $convertedUnit is impossible")
continue#loopcheck
}
if (originalUnit != null && convertedUnit == null) {
println("Conversion from $originalUnit to ??? is impossible")
continue#loopcheck
}
if (originalUnit == null && convertedUnit == null) {
println("Conversion from ??? to ??? is impossible")
continue#loopcheck
}
if (originalUnit != null && convertedUnit != null) {
if (originalUnit.type != convertedUnit.type) {
println("Conversion from ${originalUnit.plural} to ${convertedUnit.plural} is impossible")
continue#loopcheck
} else {
// Conversion Calculus
conversion = originalNumber * originalUnit.ratio / convertedUnit.ratio
// Check if the units are singular or plural
val preUnitCheck = if (originalNumber == 1.0) originalUnit.singular else originalUnit.plural
val postUnitCheck = if (conversion == 1.0) convertedUnit.singular else convertedUnit.plural
// Prints final text
println("$originalNumber $preUnitCheck is $conversion $postUnitCheck")
}
}
}
}
// Function to organize userInput in 3 variables: Number Unit1 Unit2
fun userInputSplit(userInput: String): Triple<Double?, Unidade?, Unidade?> {
val userInputArray = userInput.lowercase().split(" ")
val originalNumber = try {
userInputArray[0].toDouble()
} catch (e: NumberFormatException) { null }
val originalUnit = try {
getUnit(userInputArray[1])
} catch (e: IllegalArgumentException) { null }
val convertedUnit = try {
getUnit(userInputArray[2])
} catch (e: IllegalArgumentException) { null }
return Triple(originalNumber, originalUnit, convertedUnit)
}
// Function to set constant from Unidade for conversion based from User Input.
fun getUnit(unit: String): Unidade =
when (unit) {
"m", "meter", "meters" -> Unidade.METER
"km", "kilometer", "kilometers" -> Unidade.KILOMETER
"cm", "centimeter", "centimeters" -> Unidade.CENTIMETER
"mm", "millimeter", "millimeters" -> Unidade.MILLIMETER
"mi", "mile", "miles" -> Unidade.MILE
"yd", "yard", "yards" -> Unidade.YARD
"ft", "foot", "feet" -> Unidade.FOOT
"in", "inch", "inches" -> Unidade.INCH
"g", "gram", "grams" -> Unidade.GRAM
"kg", "kilogram", "kilograms" -> Unidade.KILOGRAM
"mg", "milligram", "milligrams" -> Unidade.MILLIGRAM
"lb", "pound", "pounds" -> Unidade.POUND
"oz", "ounce", "ounces" -> Unidade.OUNCE
// "degree celsius", "degrees celsius", "celsius", "dc", "c" -> Unit.CELSIUS
// "degree fahrenheit", "degrees fahrenheit", "fahrenheit", "df", "f" -> Unit.FAHRENHEIT
// "kelvin", "kelvins", "k" -> Unit.Kelvin
else -> throw IllegalArgumentException ("Wrong Unit. Try Again.")
}
enum class Unidade (val short: String,
val singular: String,
val plural: String,
val ratio: Double,
val type: String
) {
METER("m","meter", "meters", 1.0, "Length"),
KILOMETER("km","kilometer", "kilometers", 1000.0, "Length"),
CENTIMETER("cm","centimeter", "centimeters", 0.01, "Length"),
MILLIMETER("mm", "millimeter", "millimeters", 0.001, "Length"),
MILE("mi","mile", "miles", 1609.35, "Length"),
YARD("yd","yard", "yards", 0.9144, "Length"),
FOOT("ft","foot", "feet", 0.3048, "Length"),
INCH("in","inch", "inches", 0.0254, "Length"),
GRAM("g", "gram", "grams", 1.0, "Weight"),
KILOGRAM("kg", "kilogram", "kilograms", 1000.0, "Weight"),
MILLIGRAM("mg", "milligram", "milligrams", 0.001, "Weight"),
POUND("lb", "pound", "pounds", 453.592, "Weight"),
OUNCE("oz","ounce", "ounces", 28.3495, "Weight");
//CELSIUS("degree Celsius", "degrees Celsius", 1.0, "Temperature"),
//KELVIN("Kelvin", "Kelvins", 1.0, "Temperature"),
//FAHRENHEIT("degree Fahrenheit", "degrees Fahrenheit", 1.0, "Temperature")
}
Every time I try to check my code with Hyperskill, this happens now:
Failed to launch checking
FAILURE: Build failed with an exception.
What went wrong:
Execution failed for task ':Unit_Converter-task:compileTestKotlin'.
Error while evaluating property 'filteredArgumentsMap' of task ':Unit_Converter-task:compileTestKotlin'
Could not resolve all files for configuration ':Unit_Converter-task:testCompileClasspath'.
> Could not find com.github.hyperskill:hs-test:release-SNAPSHOT.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/com/github/hyperskill/hs-test/release-SNAPSHOT/maven-metadata.xml
- https://repo.maven.apache.org/maven2/com/github/hyperskill/hs-test/release-SNAPSHOT/hs-test-release-SNAPSHOT.pom
- https://jitpack.io/com/github/hyperskill/hs-test/release-SNAPSHOT/maven-metadata.xml
- https://jitpack.io/com/github/hyperskill/hs-test/release-SNAPSHOT/hs-test-release-v8-g6845035-132-v8-g6845035-132.pom
Required by:
project :Unit_Converter-task
Try:
Run with --stacktrace option to get the stack trace.
Run with --info or --debug option to get more log output.
Run with --scan to get full insights.
Get more help at https://help.gradle.org
BUILD FAILED in 16s
Task :Unit_Converter-task:compileKotlin
Task :Unit_Converter-task:compileJava NO-SOURCE
Task :Unit_Converter-task:processResources NO-SOURCE
Task :Unit_Converter-task:classes UP-TO-DATE
Task :util:compileKotlin NO-SOURCE
Task :util:compileJava NO-SOURCE
Task :util:processResources NO-SOURCE
Task :util:classes UP-TO-DATE
Task :util:compileTestKotlin NO-SOURCE
Task :util:compileTestJava NO-SOURCE
Task :util:processTestResources NO-SOURCE
Task :util:testClasses UP-TO-DATE
Task :Unit_Converter-task:compileTestKotlin FAILED
2 actionable tasks: 2 executed
Open the build.gradle file in the root directory of your JetBrains Academy project and replace testImplementation 'com.github.hyperskill:hs-test:release-SNAPSHOT' with testImplementation 'com.github.hyperskill:hs-test:master-SNAPSHOT'.
After reaching JETBRAINS support we did some actions. In the end, the problem was solved. Down below the steps taken.
1st try:
Open build.gradle in your project folder and replace
testImplementation 'com.github.hyperskill:hs-test:release-SNAPSHOT'
with testImplementation
'com.github.hyperskill:hs-test:master-SNAPSHOT'
The build output after the modification changed to a different error message.
Compilation Failed e: C:\Users\rafam\IdeaProjects\Unit Converter\Unit
Converter\task\test\Task2Test.kt: (6, 1): Conflicting overloads:
public fun authorsCase(input: String, isPrivate: Boolean = ...):
TestCase defined in root package in file Task2Test.kt,
public fun authorsCase(input: String, isPrivate: Boolean = ...):
TestCase defined in root package in file Task4Test.kt e:
C:\Users\rafam\IdeaProjects\Unit Converter\Unit
Converter\task\test\Task2Test.kt: (6, 81): Unresolved reference:
Authors e: C:\Users\rafam\IdeaProjects\Unit Converter\Unit
Converter\task\test\Task2Test.kt: (6, 90): Unresolved reference: solve
e: C:\Users\rafam\IdeaProjects\Unit Converter\Unit
Converter\task\test\Task2Test.kt: (11, 13): Overload resolution
ambiguity: public fun authorsCase(input: String, isPrivate: Boolean =
...): TestCase defined in root package in file
Task2Test.kt public fun authorsCase(input: String, isPrivate: Boolean
= ...): TestCase defined in root package in file Task4Test.kt ...
FAILURE: Build failed with an exception.
What went wrong: Execution failed for task ':Unit_Converter-task:compileTestKotlin'.
After this error, Jetbrains support suggested new steps:
Please try re-creating the project by following the steps below: Go to
the affected JetBrains Academy project’s directory and move it
somewhere else or make a backup.
On the Welcome Screen of your IDE, go to the My Courses tab. Highlight
the affected project and click ✕. Select Remove Course.
Start a JetBrains Academy project by going to the JetBrains Academy
tab in File | Learn and Teach | Browse Courses.
After that, please ensure that JDK 17 is selected as Gradle JVM in
Settings/Preferences | Build, Execution, Deployment | Build Tools |
Gradle and as Project SDK in File | Project Structure.
I've changed and updated everything as suggested and the build output changed AGAIN:
Failed to launch checking
FAILURE: Build failed with an exception.
What went wrong: Execution failed for task ':Unit_Converter-task:compileTestKotlin'.
Error while evaluating property 'filteredArgumentsMap' of task ':Unit_Converter-task:compileTestKotlin'
Could not resolve all files for configuration ':Unit_Converter-task:testCompileClasspath'.
> Could not find com.github.hyperskill:hs-test:release-SNAPSHOT.
Searched in the following locations:
- https://repo.maven.apache.org/maven2/com/github/hyperskill/hs-test/release-SNAPSHOT/maven-metadata.xml
- https://repo.maven.apache.org/maven2/com/github/hyperskill/hs-test/release-SNAPSHOT/hs-test-release-SNAPSHOT.pom
- https://jitpack.io/com/github/hyperskill/hs-test/release-SNAPSHOT/maven-metadata.xml
- https://jitpack.io/com/github/hyperskill/hs-test/release-SNAPSHOT/hs-test-release-v8-g6845035-132-v8-g6845035-132.pom
Required by:
project :Unit_Converter-task
After sending this output to Jetbrains they requested again to open build.gradle in my project folder and replace testImplementation 'com.github.hyperskill:hs-test:release-SNAPSHOT' with testImplementation 'com.github.hyperskill:hs-test:master-SNAPSHOT'.
This answer took 2-3 days to be replied. After that, the check worked.

Cucumber ParameterType not recognized by IntelliJ

I've registered a parameter:
#ParameterType(value = "Monday|Tuesday|Wednesday|Thursday|Friday|Saturday|Sunday", name = "weekday")
public WebElement weekday(String weekendDay) {
switch (weekendDay) {
case "Monday":
return driver().findElement(By.className("sel-btn-weekday0"));
case "Tuesday":
return driver().findElement(By.className("sel-btn-weekday1"));
case "Friday":
return driver().findElement(By.className("sel-btn-weekday4"));
case "Saturday":
return driver().findElement(By.className("sel-btn-weekday5"));
case "Sunday":
return driver().findElement(By.className("sel-btn-weekday6"));
}
return null;
}
I have a step: 'When add Saturday, Sunday as Weekend'
and then have a method annotated:
#When("add {weekday}, {weekday} as weekend")
When I run this with Cucumber plugin I got the error (shown below), but when I use gradle task to launch test via JUnit it passes. What can be the reason?
SEVERE: Exception while executing pickle
java.util.concurrent.ExecutionException: io.cucumber.core.exception.CucumberException: Could not create a cucumber expression for 'add {weekday}, {weekday} as Weekend'.
It appears you did not register a parameter type.

Can I pass inputs to gradle tasks?

Is it possible to pass inputs to a gradle task? For example, you can pass inputs to a java or a c program. Can I do something similar with a gradle task?
If you mean, that you need to pass some value via command line arguments, you can do it like:
customTask {
if ( project.hasProperty("someArg") ) {
println project.property("someArg")
}
}
Then run your application with this argument
gradle customTask -PsomeArg=PassedValue
Or you can make a task and get the values on execution phase, like:
def username
def password
task getCridentials << {
def console = System.console()
if (console) {
username = console.readLine('username: ')
password = console.readPassword('password: ')
} else {
logger.error "Can't get console."
}
}

Gradle: How to Display Test Results in the Console in Real Time?

I would like to see test results ( system.out/err, log messages from components being tested ) as they run in the same console I run:
gradle test
And not wait until tests are done to look at the test reports ( that are only generated when tests are completed, so I can't "tail -f" anything while tests are running )
Here is my fancy version:
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
tasks.withType(Test) {
testLogging {
// set options for log level LIFECYCLE
events TestLogEvent.FAILED,
TestLogEvent.PASSED,
TestLogEvent.SKIPPED,
TestLogEvent.STANDARD_OUT
exceptionFormat TestExceptionFormat.FULL
showExceptions true
showCauses true
showStackTraces true
// set options for log level DEBUG and INFO
debug {
events TestLogEvent.STARTED,
TestLogEvent.FAILED,
TestLogEvent.PASSED,
TestLogEvent.SKIPPED,
TestLogEvent.STANDARD_ERROR,
TestLogEvent.STANDARD_OUT
exceptionFormat TestExceptionFormat.FULL
}
info.events = debug.events
info.exceptionFormat = debug.exceptionFormat
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)"
def startItem = '| ', endItem = ' |'
def repeatLength = startItem.length() + output.length() + endItem.length()
println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
}
}
}
}
You could run Gradle with INFO logging level on the command line. It'll show you the result of each test while they are running. Downside is that you will get far more output for other tasks also.
gradle test -i
Disclaimer: I am the developer of the Gradle Test Logger Plugin.
You can simply use the Gradle Test Logger Plugin to print beautiful logs on the console. The plugin uses sensible defaults to satisfy most users with little or no configuration but also offers a number of themes and configuration options to suit everyone.
Examples
Standard theme
Mocha theme
Usage
plugins {
id 'com.adarshr.test-logger' version '<version>'
}
Make sure you always get the latest version from Gradle Central.
Configuration
You don't need any configuration at all. However, the plugin offers a few options. This can be done as follows (default values shown):
testlogger {
// pick a theme - mocha, standard, plain, mocha-parallel, standard-parallel or plain-parallel
theme 'standard'
// set to false to disable detailed failure logs
showExceptions true
// set to false to hide stack traces
showStackTraces true
// set to true to remove any filtering applied to stack traces
showFullStackTraces false
// set to false to hide exception causes
showCauses true
// set threshold in milliseconds to highlight slow tests
slowThreshold 2000
// displays a breakdown of passes, failures and skips along with total duration
showSummary true
// set to true to see simple class names
showSimpleNames false
// set to false to hide passed tests
showPassed true
// set to false to hide skipped tests
showSkipped true
// set to false to hide failed tests
showFailed true
// enable to see standard out and error streams inline with the test results
showStandardStreams false
// set to false to hide passed standard out and error streams
showPassedStandardStreams true
// set to false to hide skipped standard out and error streams
showSkippedStandardStreams true
// set to false to hide failed standard out and error streams
showFailedStandardStreams true
}
I hope you will enjoy using it.
You can add a Groovy closure inside your build.gradle file that does the logging for you:
test {
afterTest { desc, result ->
logger.quiet "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
}
}
On your console it then reads like this:
:compileJava UP-TO-DATE
:compileGroovy
:processResources
:classes
:jar
:assemble
:compileTestJava
:compileTestGroovy
:processTestResources
:testClasses
:test
Executing test maturesShouldBeCharged11DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test studentsShouldBeCharged8DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test seniorsShouldBeCharged6DollarsForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
Executing test childrenShouldBeCharged5DollarsAnd50CentForDefaultMovie [movietickets.MovieTicketsTests] with result: SUCCESS
:check
:build
Since version 1.1 Gradle supports much more options to log test output. With those options at hand you can achieve a similar output with the following configuration:
test {
testLogging {
events "passed", "skipped", "failed"
}
}
As stefanglase answered:
adding the following code to your build.gradle (since version 1.1) works fine for output on passed, skipped and failed tests.
test {
testLogging {
events "passed", "skipped", "failed", "standardOut", "standardError"
}
}
What I want to say additionally (I found out this is a problem for starters) is that the gradle test command executes the test only one time per change.
So if you are running it the second time there will be no output on test results. You can also see this in the building output: gradle then says UP-TO-DATE on tests. So its not executed a n-th time.
Smart gradle!
If you want to force the test cases to run, use gradle cleanTest test.
This is slightly off topic but I hope it will help some newbies.
edit
As sparc_spread stated in the comments:
If you want to force gradle to always run fresh tests (which might not always be a good idea) you can add outputs.upToDateWhen {false} to testLogging { [...] }. Continue reading here.
Peace.
Add this to build.gradle to stop gradle from swallowing stdout and stderr.
test {
testLogging.showStandardStreams = true
}
It's documented here.
'test' task does not work for Android plugin, for Android plugin use the following:
// Test Logging
tasks.withType(Test) {
testLogging {
events "started", "passed", "skipped", "failed"
}
}
See the following: https://stackoverflow.com/a/31665341/3521637
As a follow up to Shubham's great answer I like to suggest using enum values instead of strings. Please take a look at the documentation of the TestLogging class.
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
tasks.withType(Test) {
testLogging {
events TestLogEvent.FAILED,
TestLogEvent.PASSED,
TestLogEvent.SKIPPED,
TestLogEvent.STANDARD_ERROR,
TestLogEvent.STANDARD_OUT
exceptionFormat TestExceptionFormat.FULL
showCauses true
showExceptions true
showStackTraces true
}
}
My favourite minimalistic version based on Shubham Chaudhary answer.
Put this in build.gradle file:
test {
afterSuite { desc, result ->
if (!desc.parent)
println("${result.resultType} " +
"(${result.testCount} tests, " +
"${result.successfulTestCount} successes, " +
"${result.failedTestCount} failures, " +
"${result.skippedTestCount} skipped)")
}
}
In Gradle using Android plugin:
gradle.projectsEvaluated {
tasks.withType(Test) { task ->
task.afterTest { desc, result ->
println "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
}
}
}
Then the output will be:
Executing test testConversionMinutes [org.example.app.test.DurationTest] with result: SUCCESS
If you have a build.gradle.kts written in Kotlin DSL you can print test results with (I was developing a kotlin multi-platform project, with no "java" plugin applied):
tasks.withType<AbstractTestTask> {
afterSuite(KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
if (desc.parent == null) { // will match the outermost suite
println("Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)")
}
}))
}
Just add the following closure to your build.gradle. the output will be printed after the execution of every test.
test{
useJUnitPlatform()
afterTest { desc, result ->
def output = "Class name: ${desc.className}, Test name: ${desc.name}, (Test status: ${result.resultType})"
println( '\n' + output)
}
}
Merge of Shubham's great answer and JJD use enum instead of string
tasks.withType(Test) {
testLogging {
// set options for log level LIFECYCLE
events TestLogEvent.PASSED,
TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_OUT
showExceptions true
exceptionFormat TestExceptionFormat.FULL
showCauses true
showStackTraces true
// set options for log level DEBUG and INFO
debug {
events TestLogEvent.STARTED, TestLogEvent.PASSED, TestLogEvent.SKIPPED, TestLogEvent.FAILED, TestLogEvent.STANDARD_OUT, TestLogEvent.STANDARD_ERROR
exceptionFormat TestExceptionFormat.FULL
}
info.events = debug.events
info.exceptionFormat = debug.exceptionFormat
afterSuite { desc, result ->
if (!desc.parent) { // will match the outermost suite
def output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
def startItem = '| ', endItem = ' |'
def repeatLength = startItem.length() + output.length() + endItem.length()
println('\n' + ('-' * repeatLength) + '\n' + startItem + output + endItem + '\n' + ('-' * repeatLength))
}
}
}
}
Following on from Benjamin Muschko's answer (19 March 2011), you can use the -i flag along with grep, to filter out 1000s of unwanted lines. Examples:
Strong filter - Only display each unit test name and test result and the overall build status. Setup errors or exceptions are not displayed.
./gradlew test -i | grep -E " > |BUILD"
Soft filter - Display each unit test name and test result, as well as setup errors/exceptions. But it will also include some irrelevant info:
./gradlew test -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"
Soft filter, Alternative syntax: (search tokens are split into individual strings)
./gradlew test -i | grep -v -e "^Executing " -e "^Creating " -e "^Parsing " -e "^Using " -e "^Merging " -e "^Download " -e "^title=Compiling" -e "^AAPT" -e "^future=" -e "^task=" -e ":app:" -e "V/InstrumentationResultParser:"
Explanation of how it works:
The first command is ./gradlew test -i and "-i" means "Info/Verbose" mode, which prints the result of each test in real-time, but also displays large amounts of unwanted debug lines.
So the output of the first command, ./gradlew test -i, is piped to a second command grep, which will filter out many unwanted lines, based on a regular expression. "-E" enables the regular expression mode for a single string; "-e" enables regular expressions for multiple strings; and "|" in the regex string means "or".
In the strong filter, a unit test name and test result is allowed to display using " > ", and the overall status is allowed with "BUILD".
In the soft filter, the "-v" flag means "not containing" and "^" means "start of line". So it strips out all lines that start with "Executing " or start with "Creating ", etc.
Example for Android instrumentation unit tests, with gradle 5.1:
./gradlew connectedDebugAndroidTest --continue -i | grep -v -e \
"^Transforming " -e "^Skipping " -e "^Cache " -e "^Performance " -e "^Creating " -e \
"^Parsing " -e "^file " -e "ddms: " -e ":app:" -e "V/InstrumentationResultParser:"
Example for Jacoco unit test coverage, with gradle 4.10:
./gradlew createDebugCoverageReport --continue -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"
For Android, this works nicely:
android {
...
testOptions {
unitTests.all {
testLogging {
outputs.upToDateWhen { false }
events "passed", "failed", "skipped", "standardError"
showCauses true
showExceptions true
}
}
}
}
See Running Android unit / instrumentation tests from the console
For those using Kotlin DSL, you can do:
tasks {
named<Test>("test") {
testLogging.showStandardStreams = true
}
}
A more comprehensive response for those using th Kotlin DSL:
subprojects {
// all the other stuff
// ...
tasks.named<Test>("test") {
useJUnitPlatform()
setupTestLogging()
}
}
fun Test.setupTestLogging() {
testLogging {
events(
org.gradle.api.tasks.testing.logging.TestLogEvent.FAILED,
org.gradle.api.tasks.testing.logging.TestLogEvent.PASSED,
org.gradle.api.tasks.testing.logging.TestLogEvent.SKIPPED,
org.gradle.api.tasks.testing.logging.TestLogEvent.STANDARD_OUT,
)
exceptionFormat = org.gradle.api.tasks.testing.logging.TestExceptionFormat.FULL
showExceptions = true
showCauses = true
showStackTraces = true
addTestListener(object : TestListener {
override fun beforeSuite(suite: TestDescriptor) {}
override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(testDescriptor: TestDescriptor, result: TestResult) {}
override fun afterSuite(suite: TestDescriptor, result: TestResult) {
if (suite.parent != null) { // will match the outermost suite
val output = "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)"
val startItem = "| "
val endItem = " |"
val repeatLength = startItem.length + output.length + endItem.length
val messages = """
${(1..repeatLength).joinToString("") { "-" }}
$startItem$output$endItem
${(1..repeatLength).joinToString("") { "-" }}
""".trimIndent()
println(messages)
}
}
})
}
}
This should produce an output close to #odemolliens answers.
If you are using jupiter and none of the answers work, consider verifying it is setup correctly:
test {
useJUnitPlatform()
outputs.upToDateWhen { false }
}
dependencies {
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.7.0'
testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.7.0'
}
And then try the accepted answers
I've written a test logger for Kotlin DSL. You can put this block on your project scope build.gradle.kts file.
subprojects {
tasks.withType(Test::class.java) {
testLogging {
showCauses = false
showExceptions = false
showStackTraces = false
showStandardStreams = false
val ansiReset = "\u001B[0m"
val ansiGreen = "\u001B[32m"
val ansiRed = "\u001B[31m"
val ansiYellow = "\u001B[33m"
fun getColoredResultType(resultType: ResultType): String {
return when (resultType) {
ResultType.SUCCESS -> "$ansiGreen $resultType $ansiReset"
ResultType.FAILURE -> "$ansiRed $resultType $ansiReset"
ResultType.SKIPPED -> "$ansiYellow $resultType $ansiReset"
}
}
afterTest(
KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
println("${desc.className} | ${desc.displayName} = ${getColoredResultType(result.resultType)}")
})
)
afterSuite(
KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
if (desc.parent == null) {
println("Result: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} passed, ${result.failedTestCount} failed, ${result.skippedTestCount} skipped)")
}
})
)
}
}
}