AnyFunSuiteとMatchersを併用してScalaのテストケースを書いてみた(Scala 2.11.12 & ScalaTest 3.1.2)

ScalaTestにてAnyFunSuiteとMatchersを併用してのテストをやってみました。公式サイトの例が3.1.2では廃止あるいは非推奨になっているものも多く、3.1.2で利用可能なclassについて触れています。
2020.06.23

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

はじめに

Scalaのテストケース作成に着手し、最初に作成したテストがsbt testで正常に通過する段階まで辿り着きました。一番大変だったのは、テストケースのサンプルコードが大体古いためかDeprecatedのアラートが大量につくところです。

ScalaTestにてAnyFunSuiteMatchersを使ってのテスト記述パターンを備忘録込めてまとめました。

導入

以下のようにbuild.sbtへ追記します。

scalaVersion := "2.11.12"
libraryDependencies ++= Seq(
  "org.scalatest" %% "scalatest" % "3.1.2" % "test",
)

AnyFunSuiteについて

Getting started with FunSuite等で見かけるorg.scalatest.FunSuiteですが、ScalaTest 3.1.2では存在しません。org.scalatest.funsuite以下に用途別でFunSuiteが存在しており、必要なものをextendあるいはwithする形になります。

import org.scalatest.funsuite.AnyFunSuite

class MyTest extend AnyFunSuite {
  test("example") {
    // test case
  }
}

org.scalatest.funsuite以下のclassは以下の通りです。

InterFace Class UseCase
class AnyFunSuite StandardTest
trait AnyFunSuiteLike StandardTest
class AsyncFunSuite Async StandardTest
trait AsyncFunSuiteLike Async StandardTest
class FixtureAnyFunSuite StandardTest with Fixtures
trait FixtureAnyFunSuiteLike StandardTest with Fixtures
trait FixtureAsyncFunSuite Async StandardTest with Fixtures
trait FixtureAsyncFunSuiteLike Async StandardTest with Fixtures

Matchersについて

Using matchers等で見かける書き方も、3.1.2では正常には実行できません。

org.scalatest.matchers以下からextendあるいはwithします。

import org.scalatest.funsuite.AnyFunSuite
import org.scalatest.matchers.should.Matchers

class MyTest extends AnyFunSuite with Matchers {
  test("example") {
    val a = "a"
    a should be ("a")
  }
}

org.scalatest.matchers以下には他に幾つもの類似したClassが存在します。テストするプロパティ名や結果をまとめて一つのClassにするものもあります。

今回はorg.scalatest.matchers.should.Matchersをimportしてみました。matchers直下のClassはapplyを通す必要があり、記法のシンプルさを優先しつつ値確認を例としたかったためです。

InterFace Class UseCase
trait BeMatcher Value Check
trait Matcher Object Check
trait BePropertyMatcher Property Check
class BePropertyMatchResult Check Result Assertion
class HavePropertyMatchResult Check Result Assertion

MatcherとBeMatcherの違いは、上記例でa should be ("a")のうち、shouldにかかるのかbeにかかるのかの違いとなります。

具体的にはMatcherではshould以降、以下の様に値というよりも振る舞いそのものを確認します。

file should endWithExtension ("txt")
file should not endWithExtension "txt"
file should (exist and endWithExtension ("txt"))

BeMatcherではbe以降、結果そのものを一致確認します。

num should be (odd)
num should not be (even)

Although BeMatcher and Matcher represent very similar concepts, they have no inheritance relationship because Matcher is intended for use right after should or must whereas BeMatcher is intended for use right after be.

あとがき

最新のpackage構成を追従しているドキュメントはそこまで多くなく、実際にコード上でimportする際にDeprecatedを避けていくと自然に今回のClassを使う形となりました。

matchersには幾つものClassがありますが、設計全体よりも出力値のテストを重点的に求められているのならshould.Matchersを使うと柔軟にテスト可能だと感じました。

また、must.Matchersも存在しますが、shouldとmustでの振る舞いにほぼ差がないようで好みの問題かもしれません。今回shouldを使った理由としては、検証作業中に読んだ記事で利用例が多かったというだけです。

// いずれも3以外は失敗する
result must equal (3)
result should equal (3)
result must be (3)
result should be (3)

参考リンク