我有一个在travis-ci上运行的大型测试套件,其具有文本输出。 我希望以某种方式配置gradle,以便仅对于失败的测试,显示标准输出和标准错误流。 对于所有其他已正确执行的测试,不应发生这种情况,以免控制台被那些噪音污染。
我知道如何启用或禁用标准输出/错误日志记录,但我不确定如何根据测试结果使其发生。
我有一个在travis-ci上运行的大型测试套件,其具有文本输出。 我希望以某种方式配置gradle,以便仅对于失败的测试,显示标准输出和标准错误流。 对于所有其他已正确执行的测试,不应发生这种情况,以免控制台被那些噪音污染。
我知道如何启用或禁用标准输出/错误日志记录,但我不确定如何根据测试结果使其发生。
project.test {
def outputCache = new LinkedList<String>()
beforeTest { TestDescriptor td -> outputCache.clear() } // clear everything right before the test starts
onOutput { TestDescriptor td, TestOutputEvent toe -> // when output is coming put it in the cache
outputCache.add(toe.getMessage())
while (outputCache.size() > 1000) outputCache.remove() // if we have more than 1000 lines -> drop first
}
/** after test -> decide what to print */
afterTest { TestDescriptor td, TestResult tr ->
if (tr.resultType == TestResult.ResultType.FAILURE && outputCache.size() > 0) {
println()
println(" Output of ${td.className}.${td.name}:")
outputCache.each { print(" > $it") }
}
}
}
events /*'started',*/ 'passed', 'failed'
的原因。只有这样才能真正减少输出,因为 standard_*
不是给定值的一部分。 - Thorsten Schöning将以下配置块添加到您的build.gradle文件中:
import org.gradle.api.tasks.testing.logging.TestExceptionFormat
import org.gradle.api.tasks.testing.logging.TestLogEvent
tasks.withType(Test) {
testLogging {
events TestLogEvent.FAILED,
TestLogEvent.SKIPPED,
TestLogEvent.STANDARD_ERROR,
TestLogEvent.STANDARD_OUT
exceptionFormat TestExceptionFormat.FULL
showCauses true
showExceptions true
showStackTraces true
showStandardStreams true
}
}
文档可以在这里找到。
import my.conventions.FailedTestLogger.Companion.logStdOutOnFailure
// ...
tasks {
withType<Test>().configureEach {
useJUnitPlatform()
testLogging {
showStackTraces = true
exceptionFormat = TestExceptionFormat.FULL
events = setOf(
TestLogEvent.FAILED,
TestLogEvent.SKIPPED,
)
}
logStdOutOnFailure()
}
}
package my.conventions
import org.gradle.api.logging.Logging
import org.gradle.api.tasks.testing.AbstractTestTask
import org.gradle.api.tasks.testing.TestDescriptor
import org.gradle.api.tasks.testing.TestListener
import org.gradle.api.tasks.testing.TestOutputEvent
import org.gradle.api.tasks.testing.TestOutputListener
import org.gradle.api.tasks.testing.TestResult
import java.util.concurrent.ConcurrentHashMap
/**
* Only logs test output when a test fails.
*
* Example configuration
*
* ```kotlin
* tasks.test {
* useJUnitPlatform()
* testLogging {
* showStackTraces = true
* exceptionFormat = TestExceptionFormat.FULL
* events = setOf(
* TestLogEvent.FAILED,
* TestLogEvent.SKIPPED,
* )
* }
* logStdOutOnFailure()
* }
* ```
*/
class FailedTestLogger : TestListener, TestOutputListener {
private val testOutputs: MutableMap<TestDescriptor, MutableList<TestOutputEvent>> = ConcurrentHashMap()
override fun beforeSuite(test: TestDescriptor) {
}
override fun afterSuite(testDescriptor: TestDescriptor, testResult: TestResult) {
testOutputs.clear()
}
override fun beforeTest(testDescriptor: TestDescriptor) {}
override fun afterTest(test: TestDescriptor, result: TestResult) {
if (result.resultType === TestResult.ResultType.FAILURE) {
LOGGER.error(buildString {
append("## FAILURE: ")
test.className?.let {
append(it)
append(".")
}
append(test.displayName)
})
for (output in testOutputs.getOrDefault(test, listOf())) {
when (output.destination) {
TestOutputEvent.Destination.StdOut -> print(output.message)
TestOutputEvent.Destination.StdErr -> System.err.print(output.message)
}
}
for (exception in result.exceptions) {
exception.printStackTrace()
}
}
testOutputs.remove(test)
}
override fun onOutput(test: TestDescriptor, outputEvent: TestOutputEvent) {
testOutputs.compute(test) { _, value ->
(value ?: mutableListOf()).also {
it.add(outputEvent)
}
}
}
companion object {
private val LOGGER = Logging.getLogger(FailedTestLogger::class.java)
/**
* Configure the test task to only logs test output when a test fails.
*
* Should be used at the end.
*/
fun AbstractTestTask.logStdOutOnFailure() {
if (!project.providers.systemProperty("idea.active").map { it.toBoolean() }.getOrElse(false)) {
testLogging {
showStandardStreams = false
}
FailedTestLogger().also {
addTestListener(it)
addTestOutputListener(it)
}
}
}
}
}