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

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

gradle test

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

【问题讨论】:

标签: testing console gradle


【解决方案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 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))
                         }
                     }
                 }
              }
              

              【讨论】:

              • 我请求您为您的答案添加更多上下文。仅代码或仅链接的答案很难理解。如果您可以在帖子中添加更多信息,这将对提问者和未来的读者都有帮助。
              【解决方案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://stackoverflow.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 过滤掉成千上万不需要的行。见stackoverflow.com/questions/3963708/…
                  猜你喜欢
                  • 2016-08-23
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 1970-01-01
                  • 2023-02-25
                  • 1970-01-01
                  • 2012-02-11
                  • 1970-01-01
                  相关资源
                  最近更新 更多