Модульное тестирование Scala stdin / stdout

Является ли стандартной практикой модульное тестирование 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, если это имеет значение.


person Caballero    schedule 15.06.2014    source источник


Ответы (3)


Поскольку Scala за кулисами использует стандартный поток Java (System.out, System.in), вы можете протестировать его, заменив стандартные потоки своим пользовательским потоком, который вы можете дополнительно проверить. См. здесь Больше подробностей.

На самом деле, хотя я бы в первую очередь сосредоточился на том, чтобы убедиться, что doSomethingWithInput полностью протестирован, и, возможно, затем проверим чтение ввода (чтобы убедиться, что условие остановки и построение входной строки работают должным образом).

Если вы уже протестировали значение, которое собираетесь println, то проверка того, что оно было отправлено в консольный поток, дает очень мало пользы при больших усилиях. Более того, такие тестовые примеры будут непросто поддерживать в будущем. Как всегда, это зависит от вашего варианта использования, но в большинстве случаев я бы просто воздержался от тестирования.

person Norbert Radyk    schedule 15.06.2014
comment
Обратите внимание, что подход к перенаправлению стандартных потоков для Java, упомянутый выше, не работает согласованно для Scala. См. здесь, почему вам следует использовать, например, Console.withOut или Console.setOut (устарело в 2.11). См. Также этот ответ. - person Rusty Shackleford; 15.07.2015

Объект Console предоставляет методы withIn и withOut, позволяющие временное перенаправление stdin и stdout. Вот рабочий пример, который тестирует метод vulcanIO, который одновременно читает и печатает в stdin / stdout:

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"))
person Mario Galic    schedule 10.06.2019

Я бы изменил doSomethingWithInput на параметр BufferedSource в качестве параметра, чтобы вы могли писать свои модульные тесты с любым исходным потоком, а не только с stdin

person spew    schedule 15.06.2014
comment
Но doSomethingWithInput принимает String в качестве параметра (результат параметра mkString("\n") call). IMHO its a bit easier to unit test string manipulations with String`, а не BufferedSource. - person Norbert Radyk; 15.06.2014