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

Posted

技术标签:

【中文标题】Gradle:如何在控制台中实时显示测试结果?【英文标题】:Gradle: How to Display Test Results in the Console in Real Time? 【发布时间】:2011-04-27 04:41:59 【问题描述】:

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

gradle test

不要等到测试完成后再查看测试报告(仅在测试完成时生成,所以在测试运行时我不能“tail -f”任何东西)

【问题讨论】:

另请参阅***.com/questions/45856846/…,了解通过初始化脚本添加测试输出的示例,以便任何项目都可以免费获得它。 【参考方案1】:

我为 Kotlin DSL 编写了一个测试记录器。您可以将此块放在您的项目范围build.gradle.kts 文件中。

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

【讨论】:

【参考方案2】:

为使用 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 答案的输出。

【讨论】:

【参考方案3】:

对于 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

【讨论】:

【参考方案4】:

从 Benjamin Muschko's answer(2011 年 3 月 19 日)开始,您可以使用 -i 标志和 grep 来过滤掉数千条不需要的行。例子:

强过滤器 - 仅显示每个单元测试名称和测试结果以及整体构建状态。不显示设置错误或异常。

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

工作原理说明:

第一个命令是./gradlew test -i"-i" 表示“信息/详细”模式,实时打印每个测试的结果,但也显示大量不需要的调试行。

所以第一个命令./gradlew test -i 的输出通过管道传送到第二个命令grep,它将根据正则表达式过滤掉许多不需要的行。 "-E" 为单个字符串启用正则表达式模式; "-e" 启用多个字符串的正则表达式;而正则表达式字符串中的"|" 表示“或”。

在强过滤器中,允许使用" &gt; "显示单元测试名称和测试结果,使用"BUILD"允许显示整体状态。

在软过滤器中,"-v" 标志表示"not containing","^" 表示“行首”。所以它会去掉所有以“Executing”开头的行或以“Creating”开头的行,等等。


带有 gradle 5.1 的 Android 仪器单元测试示例:

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

Jacoco 单元测试覆盖率示例,使用 gradle 4.10:

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

【讨论】:

这里还有一个建议,如果您只对测试结果感兴趣:...grep -e "^.*\..*\..*&gt;.*\[.*\].*" for output of 'com.your.package.. > test_check_correct[AVD_NAME] SUCCESS' only . (或...grep -e "^.*\..*\..*&gt;.*\[.*\].*\|^&gt; Task :.*" 还包括 > Task :app:mergeDexMinApi14Debug 行)【参考方案5】:

如果您使用的是 jupiter 并且所有答案都不起作用,请考虑验证它是否设置正确:

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'

然后尝试接受的答案

【讨论】:

【参考方案6】:

对于那些使用 Kotlin DSL 的人,你可以这样做:

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

【讨论】:

【参考方案7】:

只需将以下闭包添加到您的 build.gradle。每次测试执行后都会打印输出。

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

【讨论】:

Could not find method test() for arguments ... 你把这个闭包放在哪里?以及哪个 build.gradle 文件?【参考方案8】:

如果你有一个用 Kotlin DSL 编写的build.gradle.kts,你可以打印测试结果(我正在开发一个 kotlin 多平台项目,没有应用“java”插件):

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

【讨论】:

您是否通过命令行使用./gradlew test 之类的内容调用了此任务?我试过了,但通过命令行调用时没有看到任何输出。 是的,我正在使用命令行调用此任务。在撰写我的答案时,这正在使用 gradle 版本......现在该项目不再受我的控制,我不知道 mantainers 做了什么。对不起。【参考方案9】:

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

您可以简单地使用Gradle Test Logger Plugin 在控制台上打印漂亮的日志。该插件使用合理的默认值来满足大多数用户只需很少或没有配置,但还提供了许多主题和配置选项以适合每个人。

示例

标准主题

摩卡主题

用法

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

我希望你会喜欢使用它。

【讨论】:

不错!通过/失败/跳过的测试的总结如此简单的事情导致了它。 我刚刚集成了插件,但我没有看到测试的持续时间,就像在你的 git 中括号中的每个测试一样(1.6s)如何启用它? @HaroldL.Brown 确实是 :) 我现在只是有点忙于一些事情,但它非常活跃。 是的@VadymTyemirov。与github.com/radarsh/gradle-test-logger-plugin/issues/137 相同,一旦我记录了它? 对于多模块项目添加到根 build.gradle: plugins id 'com.adarshr.test-logger' version '2.1.0' subprojects apply plugin: 'com.adarshr.test-记录器'【参考方案10】:

这是我喜欢的版本:

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

【讨论】:

在我看来,这是最好的答案。它包含最大的选项集,每个人都可以根据需要配置他们的测试。 @sealskej 我需要将此代码复制到哪里以及如何从命令行运行它?编辑:知道了 - 只需将其添加到模块的 gradle.config 并正常运行 你是如何启用颜色的? @DurgaSwaroop 对我来说开箱即用。请确保您的终端应用程序支持颜色。我个人使用 iTerm2 应用程序。 使用 Gradle 4.5 就像一个魅力【参考方案11】:

您可以在 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"
    

【讨论】:

这只会在测试执行后产生输出。我正在寻找的是查看日志记录/报告/系统输出/printlns 等。因为测试正在运行。考虑使用 maven 或仅在 IntelliJ / Eclipse 中执行测试:输出是实时生成的。 好的,很抱歉误解了您的问题。对于这种情况,您应该查看 Gradle 文档的以下部分:gradle.org/logging.html#sec:external_tools 那么我实际上做了什么改变才能看到输出?我在文档中看到了所有这些自定义侦听器和东西,但我不知道如何配置它。【参考方案12】:

我最喜欢的基于 Shubham Chaudhary 答案的简约版本。

把这个放到build.gradle文件里:

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

【讨论】:

【参考方案13】:

合并Shubham's great answer 和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))
           
       
   

【讨论】:

我请求您为您的答案添加更多上下文。仅代码或仅链接的答案很难理解。如果您可以在帖子中添加更多信息,这将对提问者和未来的读者都有帮助。【参考方案14】:

作为Shubham's great answer 的后续行动,我建议使用enum 值而不是strings。请看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
    

【讨论】:

【参考方案15】:

正如 stefanglase 回答的那样:

将以下代码添加到您的 build.gradle(从 1.1 版开始)对于 passedskippedfailed 测试的输出效果很好。

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

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

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

智能毕业!

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

这有点离题,但我希望它可以帮助一些新手。

编辑

正如 sparc_spread 在 cmets 中所述:

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

和平。

【讨论】:

嘿,只是想让你知道,我找到了一种不必每次都说 gradle cleanTest test 的方法(从 Gradle 1.12 开始)。将outputs.upToDateWhen false 添加到testLogging ... 就可以了。它将强制 Gradle 每次都运行测试。我找到了这个in the Gradle forums, posted by Dockter himself。希望这会有所帮助。 我会包含 exceptionFormat "full" 以获取有关失败的详细信息,这在您使用 AssertJ 或类似库时很有用。 你可以用test --rerun-tasks代替cleanTest @gavenkoa 我认为--rerun-tasks 会让你的所有任务重新运行,而不仅仅是测试任务。 实际上,最新的 Android Studio 和 gradle 3.3 上的 cleanTest test 对我不起作用,但 --rerun-tasks 成功了。不知道为什么。但是看了这个答案确实解决了我的头疼问题,我添加了所有东西之后的f**king测试记录在哪里。【参考方案16】:

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

test 
    testLogging.showStandardStreams = true

记录在案here。

【讨论】:

? 对于任何 Kotlin 人来说,我认为是 val test by tasks.getting(Test::class) testLogging.showStandardStreams = true 【参考方案17】:

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

// Test Logging
tasks.withType(Test) 
    testLogging 
        events "started", "passed", "skipped", "failed"
    

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

【讨论】:

太棒了。仅供参考,未来的我 - 不要将其放在 android 块中,从而节省您的两分钟【参考方案18】:

在 Gradle 中使用 Android 插件:

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

【讨论】:

【参考方案19】:

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

gradle test -i

【讨论】:

这在 gradle 1.11 中不起作用。我得到了很多调试输出,但不是个别的测试结果。 那个-i会在终端上抛出一堆不相关的信息。 除了很多无用的输出外,没有任何输出的测试通过并没有显示任何内容。 您可以使用grep 过滤掉成千上万不需要的行。见***.com/questions/3963708/…

以上是关于Gradle:如何在控制台中实时显示测试结果?的主要内容,如果未能解决你的问题,请参考以下文章

从命令行运行 gradle 时如何执行和显示友好的测试输出

在 django 模板中实时显示控制台输出[关闭]

如何在JSP页面中实现对数据库的增删查改?

如何防止 DataGrip 显示来自另一个查询控制台的结果?

在导航控制器中实现滑出菜单时在哪里以及如何设置协议委托?

如何在 BizTalk 自定义管道中实现下拉列表