Junit - 如何将测试结果作为字符串获取?

Junit - how to get test result as string?

我正在尝试测试代码并获得字符串形式的结果,以便稍后将其发送到 API。

class FirstClass{
    fun main(){
        print("Hello world!")
    }
}

测试:

ort org.junit.jupiter.api.AfterEach
import org.junit.jupiter.api.BeforeEach
import org.junit.jupiter.api.Test
import java.io.ByteArrayOutputStream
import java.io.PrintStream
import kotlin.test.assertEquals


internal class FirstClassTest {

    private val outContent = ByteArrayOutputStream()
    private val errContent = ByteArrayOutputStream()
    private val originalOut = System.out
    private val originalErr = System.err

    @BeforeEach
    fun setUp() {
        System.setOut(PrintStream(outContent))
        System.setErr(PrintStream(errContent))
    }

    @AfterEach
    fun tearDown() {
        System.setOut(originalOut)
        System.setErr(originalErr)
    }

    @Test
    fun main() {
        val SUT = FirstClass()
        SUT.main()
        val testResult = assertEquals("Hello world!", outContent.toString())
        print("Test result: $testResult")
        val api = Api()
        val apiResult = api.sendResult(testResult.toString())
        print("Api result: $apiResult")
    }

}

测试通过,但是我没有看到打印的消息。如何获取字符串形式的测试结果?

这里有几个问题。主要的是:

重定向也会影响您的测试方法。

因为您已重定向 System.out,所以您的测试方法中的 print() 会转到 outContent,连同您要测试的 FirstClass.main() 的输出,而不是屏幕或任何你想要的地方。

我可以看到两个修复程序。

快速方法是让您的测试方法输出到originalOut:

originalOut.print("Test result: $testResult")

您的测试方法在执行重定向的 class 中,因此知道重定向没有问题,并且它已经可以访问 originalOut.

但是,如果可以的话,我认为更好的解决方案是重构FirstClass,这样它就不会硬编码它写入的流。例如,流可以作为参数传递;或者它可以直接 return 字符串(并且调用者可以在一个薄的未经测试的包装器中将其写入 System.out)。

这会增加工作量,但会使您的代码更灵活且更易于测试。

其他问题包括:

您正在使用 print() 而不是 println()

许多流是行缓冲的,仅在换行符后写入它们的输出,因此如果没有结果,您可能看不到任何结果。 (即使你这样做,所有的结果也会挤在一行中!)

您分配 assertEquals() 的结果。

assertEquals() 没有有用的 return 值。 (它 return Unit。)因此您的代码将简单地显示:

Test result: kotlin.Unit

相反,与所有 assert 函数一样,如果断言失败,它会抛出异常。所以没有必要存储或处理 return 值;只需调用断言就足够了。

— 这意味着通常不需要从您的测试方法中调用 print()/println()!如果出现故障,那将是显而易见的:命令行中的 运行ning 将停止并显示异常消息和堆栈跟踪; IntelliJ 在该测试旁边显示一个大红色标记; Maven 和 Gradle 将停止构建(在所有测试有 运行 之后),显示失败的次数。所以如果一切顺利,你就知道测试已经通过了。

Api 未定义。

您在上面发布的代码无法编译,因为它不包含 Api 的定义或导入。 (尽管可以删除最后几行,但不会影响问题。)

main() 是一个容易混淆的测试名称。

单元测试框架将找到并 运行 所有用 @Test 注释的测试方法。一个测试 class 通常会包含许多不同的测试方法,通常以它们所测试的方面来命名它们。 (这使得任何失败都更加清晰。)将其称为 main() 不仅无法描述正在测试的内容,而且还暗示该方法将 运行 来自测试框架之外,这可能无法正常运行。