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()
不仅无法描述正在测试的内容,而且还暗示该方法将 运行 来自测试框架之外,这可能无法正常运行。
我正在尝试测试代码并获得字符串形式的结果,以便稍后将其发送到 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()
不仅无法描述正在测试的内容,而且还暗示该方法将 运行 来自测试框架之外,这可能无法正常运行。