18

While tests are running, the number of tests run so far is ephemerally displayed, but how can I print the total number of tests that were run to the console after all tests have run?

Configuring testLogging doesn't help. I can make gradle output a result for every test, like this:

testLogging {
    events "passed", "skipped", "failed"
}

But I want a summary "bottom line", that outputs the total number of tests that were run, even if they all passed.

Bohemian
  • 412,405
  • 93
  • 575
  • 722

5 Answers5

20

You may use afterSuite closure with TestResult argument. F.e. (borrowed from https://gist.github.com/orip/4951642):

test {
  testLogging {
    afterSuite { desc, result ->
      if (!desc.parent) { // will match the outermost suite
        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
      }
    }
  }
}
Hubbitus
  • 5,161
  • 3
  • 41
  • 47
  • When I do this I get `Could not find method test() for arguments...`. Any ideas what could cause this? I put it in the app level build.gradle file. – AdamMc331 Aug 30 '18 at 21:07
  • 1
    Looks like it's a little different on Android: https://stackoverflow.com/questions/31275976/gradle-dsl-method-not-found-test/31665341#31665341 – AdamMc331 Aug 30 '18 at 21:16
  • @AdamMc331, check you applied Java plugin – Hubbitus Sep 23 '19 at 11:48
2

Using Gradle 2.12 with a simple project (with 2 test suites), this script:

apply plugin: 'java'

repositories {
    mavenCentral()
}

dependencies {
    testCompile 'junit:junit:4.12'
}

def numTests = 0

test {
    beforeTest { descriptor ->
        logger.lifecycle("Running test: " + descriptor)
        numTests++
    }
}

test << {
    println "\nnumTests executed: ${numTests}"
}

gives this output (for me):

bash$ gradle clean test
:clean
[snip]
:test
Running test: Test test1(net.codetojoy.ActorTest)
Running test: Test test2(net.codetojoy.ActorTest)
Running test: Test test3(net.codetojoy.ActorTest)
Running test: Test test4(net.codetojoy.ActorTest)
Running test: Test test1(net.codetojoy.SniffTest)
Running test: Test test2(net.codetojoy.SniffTest)
Running test: Test test3(net.codetojoy.SniffTest)
Running test: Test test4(net.codetojoy.SniffTest)
Running test: Test test5(net.codetojoy.SniffTest)
Running test: Test test6(net.codetojoy.SniffTest)

numTests executed: 10
Michael Easter
  • 23,733
  • 7
  • 76
  • 107
  • It gets the job done, but I'm looking for a configuration/setting approach - it seems reasonable that there should be a simple way of outputting it. – Bohemian May 12 '16 at 01:55
2

Kotlin DSL applied answer based on the accepted answer from @Hubbitus (was a bit trickier to adapt than expected):

tasks.withType<AbstractTestTask> {
    afterSuite(
        KotlinClosure2({ desc: TestDescriptor, result: TestResult ->
            // Only execute on the outermost suite
            if (desc.parent == null) {
                println(" **** Result: ${result.resultType} ****")
                println("  >    Tests: ${result.testCount}")
                println("  >   Passed: ${result.successfulTestCount}")
                println("  >   Failed: ${result.failedTestCount}")
                println("  >  Skipped: ${result.skippedTestCount}")
            }
        })
    )
}

Using KotlinClosure2 allows the afterSuite Groovy closure to be called with the two expected arguments (TestDescriptor and TestResult) and Unit is the return type of the closure (reference: calling groovy closure from Kotlin).

Derek Lee
  • 3,452
  • 3
  • 30
  • 39
0

Here's my Android solution based on @Hubbitus's answer and this answer

subprojects {
    afterEvaluate { project ->
        if (project.plugins.findPlugin('android') ?: project.plugins.findPlugin('android-library')) {
            tasks.withType(Test) {
                testLogging {
                    events "started", "passed", "skipped", "failed"

                }
                afterSuite { desc, result ->
                    if (!desc.parent) { // will match the outermost suite
                        println "Results: ${result.resultType} (${result.testCount} tests, ${result.successfulTestCount} successes, ${result.failedTestCount} failures, ${result.skippedTestCount} skipped)"
                    }
                }
            }
        }
    }
}

Which goes in my root build.gradle

aaronmarino
  • 3,723
  • 1
  • 23
  • 36
0

Gradle writes XML files in test-reports that are easy to parse. You can for an example parse them with a Kotlin script:

@file:DependsOn("net.mbonnin.xoxo:xoxo:0.3")

import xoxo.toXmlDocument
import java.io.File

File(".").walk().filter { it.name == "test-results" && it.isDirectory }
    .toList()
    .flatMap {
      it.walk().filter { it.isFile && it.extension == "xml" }.toList()
    }
    .map {
       it.toXmlDocument()
          .root
          .attributes["tests"]!!
          .toInt()
    }
    .sum()
mbonnin
  • 6,893
  • 3
  • 39
  • 55