Scala单元测试标准输入/输出

5

单元测试 stdIn/stdOut 是常见实践吗?如果是,那么如何测试这样的内容:

import scala.io.StdIn._

object Test {

    def main(args: Array[String]) = {

        println("Please input your text. Leaving an empty line will indicate end of the input.")

        val input = Iterator.continually(readLine()).takeWhile(_ != "").mkString("\n")

        val result = doSomethingWithInput(input)

        println("Result:")
        println(result)

    }

}

如果有所不同的话,我通常使用ScalaTest。

3个回答

6

Console对象提供withInwithOut方法,可以临时重定向标准输入和标准输出。以下是一个工作示例,测试了vulcanIO方法,该方法同时读取和打印标准输入和标准输出:

import java.io.{ByteArrayOutputStream, StringReader}
import org.scalatest._
import scala.io.StdIn

class HelloSpec extends FlatSpec with Matchers {
  def vulcanIO(): Unit = {
    println("Welcome to Vulcan. What's your name?")
    val name = StdIn.readLine()
    println("What planet do you come from?")
    val planet = StdIn.readLine()
    println(s"Live Long and Prosper , $name from $planet.")
  }

  "Vulcan salute" should "include , name, and planet" in {
    val inputStr =
      """|Jean-Luc Picard
         |Earth
      """.stripMargin
    val in = new StringReader(inputStr)
    val out = new ByteArrayOutputStream()
    Console.withOut(out) {
      Console.withIn(in) {
        vulcanIO()
      }
    }
    out.toString should (include ("") and include ("Jean-Luc Picard") and include ("Earth"))
  }
}

请注意重定向是如何发生在内部的。
Console.withOut(out) {
  Console.withIn(in) {
    vulcanIO()
  }
}

我们需要在输出流out上进行断言。

out.toString should (include ("") and include ("Jean-Luc Picard") and include ("Earth"))

6

由于Scala在后台使用标准的Java流(System.out, System.in),因此您可以通过替换标准流为自定义流进行测试,并进一步检查它。详情请参见这里

实际上,我主要关注确保doSomethingWithInput得到充分测试,然后再测试输入读取(以确保停止条件和输入字符串构造按预期工作)。

如果您已经测试了要输出的值,那么确保它已发送到控制台流将获得很少的收益,但需要付出很大的努力来维护这样的测试用例。总之,这取决于您的用例,但在大多数情况下,我会避免测试它。


请注意,上述重定向Java标准流的方法在Scala中不一致。请参见此处,了解为什么应该使用例如Console.withOutConsole.setOut(在2.11中已弃用)。另请参见此答案 - Rusty Shackleford

0
我会将 doSomethingWithInput 更改为以 BufferedSource 作为参数,这样您就可以使用任何源流编写单元测试,而不仅仅是标准输入。

但是 doSomethingWithInput 接受 String 作为参数(即 mkString("\n") 调用的结果)。在我看来,使用 String 参数进行单元测试比使用 BufferedSource 更容易进行字符串操作。 - Norbert Radyk

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接