プロパティベーステスト
ScalaCheck です。
「プロパティベーステスト」はCoddyKit上の無料Scala for Backend Engineering & Functional Programmingレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応のAIチューターでハンズオン演習できます。 これはScala for Backend Engineering & Functional Programming学習パスの一部であり、ウェブとCoddyKitアプリ全体で進捗が同期されます。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
プロパティベーステストとは
プロパティベーステストでは、すべての入力で成り立つ一般的なプロパティを定義し、フレームワークが多数のランダムな入力を生成して、それが成り立たないケースを探します。手書きの例では見逃しやすいエッジケースを見つけられます。
例とプロパティの違い
例によるテストは1つのケースを確認します。例:reverse(List(1,2,3)) == List(3,2,1)。一方、プロパティは規則を表します。どのようなリストでも、2回反転すると元のリストになるという規則です。フレームワークは、生成した何百ものリストでその規則を確認します。
ScalaCheck
ScalaCheckはScala向けのプロパティテストライブラリです。テスト依存関係として追加すると、ScalaTestと統合して使えます。
libraryDependencies += "org.scalatestplus" %% "scalacheck-1-17" % "3.2.18.0" % TestforAll
中心となる構造はforAllです。ランダムな値を生成し、それぞれに対してプロパティ本体をアサートします。ここでは加算が可換であることをテストします。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
class AddSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
"addition" should "be commutative" in {
forAll { (a: Int, b: Int) =>
a + b shouldBe b + a
}
}
}ラウンドトリッププロパティ
強力なパターンの1つがラウンドトリップです。任意の入力に対して、エンコードしてからデコードする(または2回反転する)と、元の値に戻ることを確認します。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
class RevSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
"reverse" should "be its own inverse" in {
forAll { (xs: List[Int]) =>
xs.reverse.reverse shouldBe xs
}
}
}ジェネレーター
ScalaCheckは、組み込み型向けのGenジェネレーターを自動的に提供します。カスタムジェネレーターを作ることもできます。たとえばGen.choose(1, 100)は範囲を限定した整数を生成します。
import org.scalacheck.Gen
val smallInt: Gen[Int] = Gen.choose(1, 100)
val nonEmpty: Gen[List[Int]] = Gen.nonEmptyListOf(Gen.choose(0, 9))カスタムジェネレーターの使用
ジェネレーターをforAllに渡して入力を制限できます。たとえば、正の数だけを対象にできます。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
import org.scalacheck.Gen
class PosSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
"abs" should "stay positive" in {
forAll(Gen.choose(1, 1000)) { (n: Int) =>
math.abs(n) should be > 0
}
}
}シュリンキング
プロパティが失敗すると、ScalaCheckは失敗し続ける最小の例まで入力を縮小します。巨大なランダムリストの代わりに、デバッグしやすい最小限の反例が得られます。
条件付きプロパティ
wheneverを使うと、前提条件を満たす入力にプロパティの対象を限定できます。条件を満たさない入力は破棄されます。
import org.scalatest.flatspec.AnyFlatSpec
import org.scalatest.matchers.should.Matchers
import org.scalatestplus.scalacheck.ScalaCheckPropertyChecks
class DivSpec extends AnyFlatSpec with Matchers with ScalaCheckPropertyChecks {
"division" should "hold for nonzero divisors" in {
forAll { (a: Int, b: Int) =>
whenever(b != 0) {
(a / b) * b + (a % b) shouldBe a
}
}
}
}テストに適したプロパティ
役立つプロパティの種類:
- ラウンドトリップ:エンコード/デコード、反転/反転。
- 不変条件:ソートしても長さが変わらない。
- 代数法則:可換律、結合律、単位元。
いつ使うか
プロパティテストは例によるテストを補完するものであり、置き換えるものではありません。明確な数学的ルールや構造的ルールを持つ純粋関数に使ってください。特定の既知のケースやリグレッションについては、対象を絞った例によるテストも残します。
クイックチェック
プロパティベーステストについての知識を確認しましょう。
まとめ
ScalaCheckを使ったプロパティベーステストについて学びました。
- すべての入力で真となるプロパティを定義し、フレームワークに多数の入力を生成させます。
forAllが生成を実行し、Genでカスタム入力を作成します。wheneverで前提条件を追加し、失敗した入力は縮小されて最小限の例になります。- ラウンドトリップ、不変条件、代数法則のテストに適しています。
よくある質問
「プロパティベーステスト」レッスンは無料ですか?
はい。「プロパティベーステスト」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Scala for Backend Engineering & Functional Programmingコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Scala for Backend Engineering & Functional Programmingコースには全4レッスンが含まれています。
「プロパティベーステスト」で何を学びますか?
ScalaCheck です。 ブラウザで直接実行するハンズオンコードでScala for Backend Engineering & Functional Programmingを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Scala for Backend Engineering & Functional Programmingを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのScala for Backend Engineering & Functional Programmingは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「プロパティベーステスト」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このScala for Backend Engineering & Functional Programmingレッスンでコードを書いて実行できますか?
はい。すべてのScala for Backend Engineering & Functional Programmingレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- ScalaTest のスタイル
- Matchers
- プロパティベーステスト
- モックとフィクスチャ