Lambdaカクテル

京都在住Webエンジニアの日記です

Invite link for Scalaわいわいランド

ScalaTestでテーブルテストをやりたかったらforAllを使うといいぞ

こういう感じで書けます。

import org.scalatest.prop.TableDrivenPropertyChecks
import org.scalatest.funspec.AnyFunSpec

// 必要なのは TableDrivenPropertyChecks なので、あとは好きなstyleを選んでよい
class FooSpec extends AnyFunSpec with TableDrivenPropertyChecks {
  describe("foo") {
    it("bar") {
      // テーブルを定義する。
      // たまに名前かぶるのでTestTableにしている。
      import org.scalatest.prop.TableDrivenPropertyChecks.{Table => TestTable}
      val testTable = TestTable(
        ("lhs", "rhs", "result", "msg"), // 1要素目はヘッダ
        // Tupleが1つのテストケースにあたる
        (0    , 1    , 1       , "zero plus one is one"),
        (1    , 0    , 1       , "one plus zero is one"),
        (1    , 1    , 2       , "one plus one is two"),
        (10   , 20   , 40      , "this should be failed")
      )

      // forAllにテーブルを渡す。第2引数は1つのテストケースをTupleで受け取る関数の形をとる。
      forAll(testTable) { (lhs, rhs, result, msg) =>
        // withClueはただの見易くするためのヘルパ。
        withClue(s"$msg:") { assert(lhs + rhs == result) }
      }
    }
  }
}

ScalaTestはプロパティベーステストの一部としてテーブルを用いたプロパティベーステストを用意してくれている。

www.scalatest.org

上掲のコードでテストに失敗すると、以下のようなメッセージが表示される。

TestFailedException was thrown during property evaluation. 
  Message: this should be failed: 30 was not equal to 40
  Location: Foo.scala
  Occurred at table row 3 (zero based, not counting headings), which had values (
    lhs = 10,
    rhs = 20,
    result = 40,
    msg = this should be failed
  )

何番目のケースが落ちたかも教えてくれて便利。rowはヘッダを除いて0ベースで数える。

テストがコケたときにテストケースを探すのは大変なので、自分はwithClueを使って補足情報としてmsgを追加出力している。withClueは、その範囲でテストが落ちたときのメッセージの頭に特定の文字列を挿入してくれるユーティリティ。なのでエラーメッセージもMessage: this should be failed: 30 was not equal to 40のようになっている。

Generatorを使ったプロパティベーステストを行う場合にはScalaCheckが必要になるが、テーブルを用いたプロパティベーステストの場合、ScalaCheckは必要ない。

★記事をRTしてもらえると喜びます
Webアプリケーション開発関連の記事を投稿しています.読者になってみませんか?