293

我想查看测试结果(system.out/err,来自正在测试的组件的日志消息),因为它们在我运行的同一控制台中运行:

gradle test

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

4

19 回答 19

218

这是我喜欢的版本:

花哨的测试结果

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))
            }
        }
    }
}
于 2016-03-21T12:00:42.800 回答
211

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

gradle test -i
于 2011-03-19T14:01:17.530 回答
181

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

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

例子

标准主题 标准主题

摩卡主题 摩卡主题

用法

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

确保您始终从 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
}

我希望你会喜欢使用它。

于 2017-10-02T20:21:59.213 回答
171

您可以在 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 支持更多选项来记录测试输出。使用手头的这些选项,您可以使用以下配置实现类似的输出:

test {
    testLogging {
        events "passed", "skipped", "failed"
    }
}
于 2010-11-27T16:56:19.820 回答
143

正如stefanglase回答的那样:

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

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

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

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

智能毕业!

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

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

编辑

正如评论中所说的sparc_spread

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

和平。

于 2013-12-03T19:04:27.090 回答
61

添加这个以build.gradle阻止 gradle 吞下 stdout 和 stderr。

test {
    testLogging.showStandardStreams = true
}

它记录在这里

于 2015-01-21T13:31:13.073 回答
44

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

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

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

于 2015-07-28T09:21:33.667 回答
21

作为Shubham 出色答案的后续行动,我建议使用enum values 而不是strings。请查看TestLogging 类的文档

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
    }
}
于 2016-03-24T11:37:29.383 回答
17

我最喜欢的基于 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)")
    }
}
于 2017-05-31T15:16:19.917 回答
7

在 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] 结果:成功

于 2015-09-08T15:34:07.590 回答
5

如果你有一个build.gradle.ktsKotlin DSL编写的,你可以打印测试结果(我正在开发一个 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)")
        }
    }))
}
于 2019-11-25T10:31:40.890 回答
4

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

test{
    useJUnitPlatform()
    afterTest { desc, result ->
        def output = "Class name: ${desc.className}, Test name: ${desc.name},  (Test status: ${result.resultType})"
        println( '\n' + output)
    }
}
于 2020-06-27T15:30:28.143 回答
3

Shubham 的好答案JJD的合并使用枚举而不是字符串

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))
           }
       }
   }
}
于 2016-11-30T12:50:46.667 回答
3

对于 Android,这很好用:

android {
...

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

}

请参阅从控制台运行 Android 单元/仪器测试

于 2021-03-09T16:45:00.997 回答
2

Benjamin Muschko 的回答(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:"

解释它是如何工作的:

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

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

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

在软过滤器中,"-v"标志的意思是“不包含”"^"意思是“行首”。因此,它会删除所有以“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:"
于 2018-10-20T10:59:21.000 回答
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)")
                    }
                })
            )
        }
    }
}

在此处输入图像描述

于 2021-11-04T13:56:00.933 回答
0

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

tasks {
  named<Test>("test") {
    testLogging.showStandardStreams = true
  }
}
于 2020-07-25T04:56:20.893 回答
0

如果您使用的是 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'
}

然后尝试接受的答案

于 2020-09-30T03:53:02.847 回答
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 答案的输出。

于 2021-07-25T13:21:22.910 回答