【问题标题】:Scala unit testing stdin/stdoutScala 单元测试标准输入/标准输出
【发布时间】:2014-08-05 08:21:01
【问题描述】:

对 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。

【问题讨论】:

    标签: scala unit-testing scalatest


    【解决方案1】:

    由于 Scala 在幕后使用标准 Java 流(System.out,System.in),因此您可以通过将标准流替换为您可以进一步检查的自定义流来测试它。 See here 了解更多详情。

    实际上,虽然我主要关注的是确保 doSomethingWithInput 已经过全面测试,并且可能会跟进输入读数的测试(以确保停止条件和输入字符串构造按预期工作)。

    如果您已经测试了要发送到println 的值,那么确保它已被发送到控制台流,但付出的努力却很少。此外,这样的测试用例将是维持前进的痛苦。与往常一样,这取决于您的用例,但在大多数情况下,我会避免对其进行测试。

    【讨论】:

    • 请注意,上面提到的为 Java 重定向标准流的方法对于 Scala 并不一致。请参阅 here 了解您应该使用的原因,例如,Console.withOut 或 Console.setOut(在 2.11 中已弃用)。另见this answer。
    【解决方案2】:

    Console 对象提供了withIn 和withOut 方法,可以临时重定向标准输入和标准输出。这是一个测试方法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"))
    

    【讨论】:

      【解决方案3】:

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

      【讨论】:

      • 但是doSomethingWithInput将String作为参数(mkString("\n") call). IMHO its a bit easier to unit test string manipulations with String`参数的结果而不是BufferedSource。
      猜你喜欢
      • 1970-01-01
      • 2013-09-18
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-10-20
      • 1970-01-01
      • 2012-10-31
      • 2012-06-08
      相关资源
      最近更新 更多