0Pricing
Scala for Backend Engineering & Functional Programming · レッスン

プロパティベーステスト

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" % Test

forAll

中心となる構造は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フィードバックを取得できます。ローカル設定は不要です。

このコースのすべてのレッスン

  1. ScalaTest のスタイル
  2. Matchers
  3. プロパティベーステスト
  4. モックとフィクスチャ
← Scala for Backend Engineering & Functional Programmingに戻る