ScalaのテストフレームワークであるところのScalaTestのドキュメントを読んでいたら便利なメソッドを発見したのでメモ。実はもうみんな知ってるかもしれない。
等価性比較
ScalaTestでは、Matcherという便利なメソッドを使って等価性や存在判定などのテストを行うことができるようになっている。
import org.scalatest._ import flatspec._ import matchers._ import org.scalatest.funspec.AnyFunSpec abstract class UnitSpec extends AnyFunSpec with should.Matchers {} class FooSpec extends UnitSpec { describe("Int") { in("addition") { (1 + 1) shouldBe 2 // このshouldBeがMatcher } } }
最も良く使われるであろうMatcherが、shouldBe
マッチャーだ。
shouldBe
マッチャー
shouldBe
は、 中置演算子のように振る舞い、その等価性を判定する。等価性の判定は、以下の原則に従う:
- ArrayであればSeqに変換して
==
で比較する - それ以外の型であれば
==
で比較する
shouldBe
を使うメリットは、ほぼ型に左右されない(implicitを要求しない)ためコンパイルがもっとも高速であることだ。
should be(...)
もshouldBe
と等価だが、shouldBe
は括弧が不要なのでこちらを使ったほうが使い勝手が良いだろう。
shouldEqual
マッチャー
次点でよく使われるのがshouldEqual
マッチャーだ。
shouldEqual
はほぼshouldBe
と同じである。唯一違うのは、その振る舞いをorg.scalactic.Equality[A]
を定義することでカスタマイズ可能である点だ。
Equality
を定義するメリットは色々ある。例えばプロダクトがDDDを採用していて、「IDが同じであればエンティティとして等価とみなす」という取り決めがなされている場合、オブジェクト全体を比較するのはナンセンスだし遅い。そこで、id
だけ比較するようなEquality
を定義することで、等価性の判定を拡張できるのだ。
implicit val FooEq = new org.scalactic.Equality[Foo] { def areEqual(a: Foo, b: Any): Boolean = ??? }
このような定義を置いておくと、shouldEqual
は自動的にFooEq
を発見して等価性比較に使うようになる。
val foo1 = Foo(...) val foo2 = Foo(...) foo1 shouldEqual foo2 // FooEqが使われる
should be
同様に、should equal
という構文もあるが、shouldEqual
と書いたほうが括弧を省略できるのでこちらが便利だ。
Productやcase classの場合
Equality
は直接比較した場合にのみうまく働くようで、タプルやコレクションに入れている場合は働かない。例えば、List[Foo]
同士の比較にあたってはEquality[Foo]
は使われない・・・。この点はちょっとなんとかなってほしい。
should ===
マッチャー
あまり知られていない名マッチャーとしてshould ===
がある。これはshouldEqual
と同じだが、org.scalactic.TypeCheckedTripleEquals
と組み合わせて使うことで、左右の型が合っていることをコンパイル時に強制する。
class FooSpec extends UnitSpec { describe("Int") { in("tripleEqual") { 42 should === ("foo") // 実行時にエラーになる } } }
class FooSpec extends UnitSpec with org.scalactic.TypeCheckedTripleEquals { describe("Int") { in("tripleEqual") { 42 should === ("foo") //コンパイルエラーになる } } }
ほとんどの場合、テストでの比較対象は型が揃っているはず。テスト体験を良くするためにも、コンパイル時点で比較対象の型が合っていることを確認できる`should ===
をおすすめしたい。
他にも、implicitな関係も含めて比較してくれるConversionCheckedTripleEquals
もあるので試してみてほしい。
参考文献
https://www.scalactic.org/scaladoc/3.2.15/org/scalactic/Equality.htmlwww.scalactic.org
https://www.scalactic.org/user_guide/ConstrainedEqualitywww.scalactic.org