LoginSignup
10
7

More than 5 years have passed since last update.

print/printlnを使う関数をテストするときはConsole.withOutを使おう

Last updated at Posted at 2014-06-27

System.outConsole.outVarにキャッシュされるのを知らなかったという話です

printprintlnの両方について当てはまるので以下はprintの例だけを書きます。

printが処理される流れ

まず前提としてprintは暗黙にimport Predef._されてるPredef.printです。

Predef.scala

object Predef extends LowPriorityImplicits {
  def print(x: Any) = Console.print(x)
Console.scala
object Console {
  def print(obj: Any) {
    out.print(if (null == obj) "null" else obj.toString())
  }
  def out = outVar.value
  private val outVar = new DynamicVariable[PrintStream](java.lang.System.out)

順に辿っていくと、Console.outVarSystem.outの値で初期化されていることがわかります。

Consoleはobjectなので遅延評価(最初にメンバーへのアクセスがあった時に評価)されます

System.outはキャッシュされて、その後のSystem.setOutは効果を及ぼしません。
Console.setOutで強制的にConsole.outVar.valueを上書きすることもできますが、2.11から非推奨になっていますので、Console.withOutを使うのがいいようです。

Console.scala
object Console {
  def withOut[T](out: PrintStream)(thunk: =>T): T =
    outVar.withValue(out)(thunk)
Test.scala
"Predef.print" should {
  "print hello" in {
    val outStream = new ByteArrayOutputStream
    val out = new PrintStream(new BufferedOutputStream(outStream), true, "utf-8")
    Console.withOut(out) {
      print("hello")
      out.flush()
      outStream.toString("utf-8") mustEqual "hello"
    }
  }
}
10
7
3

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
10
7