Gradle:如何在控制台中实时显示测试结果?

时间:2010-10-18 21:53:14

标签: testing console gradle

我希望在我运行的同一个控制台中看到测试结果(system.out / err,来自正在测试的组件的日志消息)

gradle test

不要等到测试完成才能查看测试报告(仅在测试完成时生成,因此在测试运行时我不能“尾随-f”)

18 个答案:

答案 0 :(得分:137)

您可以在build.gradle文件中添加一个Groovy闭包,为您执行日志记录:

test {
    afterTest { desc, result -> 
        logger.quiet "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
    }
}

在你的控制台上它的内容如下:

: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

从版本1.1开始,Gradle支持很多more options to log test output。有了这些选项,您可以使用以下配置实现类似的输出:

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

答案 1 :(得分:132)

这是我喜欢的版本:

fancy test result

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} 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))
            }
        }
    }
}

答案 2 :(得分:131)

您可以在命令行上使用INFO日志记录级别运行Gradle。它会在运行时向您显示每个测试的结果。缺点是你也可以获得更多其他任务的输出。

gradle test -i

答案 3 :(得分:97)

stefanglase 回答:

将以下代码添加到build.gradle(从1.1版开始)可以正常处理传递跳过失败的输出测试

test {
    testLogging {
        events "passed", "skipped", "failed", "standardOut", "standardError"
    }
}

我想说的另外一点(我发现这对初学者来说是一个问题)是gradle test命令每次更改只执行一次测试

因此,如果您正在运行它第二次测试结果将没有输出。您还可以在建筑物输出中看到这一点:gradle然后在测试中说 UP-TO-DATE 。所以它没有执行第n次。

Smart gradle!

如果要强制运行测试用例,请使用gradle cleanTest test

这有点偏离主题,但我希望它能帮助一些新手。

修改

正如 sparc_spread 在评论中所述:

如果您想强制使用gradle 始终运行新的测试(这可能并不总是一个好主意),您可以将outputs.upToDateWhen {false}添加到testLogging { [...] }。继续阅读here

和平。

答案 4 :(得分:57)

免责声明:我是Gradle Test Logger插件的开发者。

您可以使用Gradle Test Logger Plugin在控制台上打印漂亮的日志。该插件提供了许多主题和配置选项,以适应大量观众。

  

注意:Gradle Test Logger插件v1.4 +现在也支持并行测试执行。只需使用suitable theme即可。

实施例

Standard Theme 标准主题

Mocha Theme 摩卡主题

用法

plugins {
    id 'com.adarshr.test-logger' version '<version>'
}

确保始终获得latest version from Gradle Central

配置

您根本不需要任何配置。但是,该插件提供了一些选项。这可以按如下方式完成(显示默认值):

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 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
}

我希望你会喜欢使用它。

答案 5 :(得分:43)

将其添加到build.gradle以阻止gradle吞下stdout和stderr。

test {
    testLogging.showStandardStreams = true
}

它已记录here

答案 6 :(得分:34)

'test'任务对Android插件不起作用,对于Android插件使用以下内容:

<img class="logoImg" src="images/logo.png" height="100" />

请参阅以下内容:https://stackoverflow.com/a/31665341/3521637

答案 7 :(得分:17)

作为Shubham's great answer的后续内容,我建议您使用 enum 值而非字符串。请查看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
    }
}

答案 8 :(得分:10)

我最喜欢的简约版本基于Shubham Chaudhary的回答。 enter image description here

将其放在build.gradle文件中:

test {
    afterSuite { desc, result ->
    if (!desc.parent)
        println("${result.resultType} " +
            "(${result.testCount} tests, " +
            "${result.successfulTestCount} successes, " +
            "${result.failedTestCount} failures, " +
            "${result.skippedTestCount} skipped)")
    }
}

答案 9 :(得分:7)

使用Android插件的Gradle:

gradle.projectsEvaluated {
    tasks.withType(Test) { task ->
        task.afterTest { desc, result ->
            println "Executing test ${desc.name} [${desc.className}] with result: ${result.resultType}"
        }
    }
}

然后输出将是:

  

执行测试testConversionMinutes [org.example.app.test.DurationTest],结果为:SUCCESS

答案 10 :(得分:3)

合并Shubham's great answerJJD 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))
           }
       }
   }
}

答案 11 :(得分:2)

Benjamin Muschko's answer(2011年3月19日)开始,您可以将-i标志与grep一起使用,以过滤掉1000条不需要的行。例子:

强大的过滤器-仅显示每个单元测试的名称和结果以及总体构建状态。安装程序错误或异常不会显示。

./gradlew test -i | grep -E " > |BUILD"

软过滤器-显示每个单元测试的名称和结果,以及设置错误/异常。但这还将包括一些不相关的信息:

./gradlew test -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"

软过滤器,另一种语法:(搜索令牌被拆分成单个字符串)

./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:"

Android工具单元测试的示例:

./gradlew connectedDebugAndroidTest --continue -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"

Jacoco单元测试范围的示例:

./gradlew createDebugCoverageReport --continue -i | grep -E -v "^Executing |^Creating |^Parsing |^Using |^Merging |^Download |^title=Compiling|^AAPT|^future=|^task=|:app:|V/InstrumentationResultParser:"

工作原理的说明:第一个命令./gradlew test -i的输出通过管道传递给第二个命令grep,该命令将根据以下内容过滤掉许多不需要的行正则表达式。 "-E"启用正则表达式模式,而"|"表示“或”。使用" > "过滤单元测试名称和结果,并使用"BUILD"过滤总体状态。在软过滤器的情况下,"-v"标志表示"not containing",而"^"则表示“行首”。因此,它会删除以“正在创建”开头或以“解析”开头的行,等等。

答案 12 :(得分:2)

只需在您的build.gradle中添加以下闭合即可。输出将在每次测试执行后打印。

test{
    useJUnitPlatform()
    afterTest { desc, result ->
        def output = "Class name: ${desc.className}, Test name: ${desc.name},  (Test status: ${result.resultType})"
        println( '\n' + output)
    }
}

答案 13 :(得分:0)

如果您有用 Kotlin DSL 编写的build.gradle.kts,则可以使用以下命令打印测试结果(我正在开发一个kotlin多平台项目,未应用“ java”插件):< / p>

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)")
        }
    }))
}

答案 14 :(得分:0)

对于使用Kotlin DSL的用户,您可以执行以下操作:

tasks {
  named<Test>("test") {
    testLogging.showStandardStreams = true
  }
}

答案 15 :(得分:0)

如果您使用的是木星并且没有任何答案,请考虑确认其设置正确:

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'
}

然后尝试接受的答案

答案 16 :(得分:0)

对于 Android,这很好用:

android {
...

testOptions {
    unitTests.all {
        testLogging {
            outputs.upToDateWhen { false }
            events "passed", "failed", "skipped", "standardError"
            showCauses true
            showExceptions true
        }
    }
} 

}

Running Android unit / instrumentation tests from the console

答案 17 :(得分:0)

对使用 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)
                }
            }
        })
    }
}

这应该会产生接近@odemolliens 答案的输出。