Scalatestでサポートされている各テストスタイルは、特定の目的に使用するように設計されています。 各テストスタイルを使用するには、このテストスタイルが定義されている特性を実装するクラスを作成する必要があります。 選択されたスタイルは、テスト宣言の外観のみを決定し、フレームワークの他のすべての機能は、どのテストスタイルが選択されたかに関係なく、同じように機能します。 著者は、ユニットテストと統合テストにFlatSpecを使用し、受け入れテストにFeatureSpecを使用することを推奨しています。そのため、他のいくつかのスタイルを例のみに示します。
フラットセペック
FlatSpecは、xUnitや他の同様のフレームワークの使用からBDDの使用に切り替えたいチームにとって良い前進です。FlatSpecは、テストされたクラスの動作仕様の記述にできるだけ近い形でテストを記述できるDSLです。
import org.scalatest.FlatSpec class SetSpec extends FlatSpec { "An empty Set" should "have size 0" in { assert(Set.empty.size == 0) } it should "produce NoSuchElementException when head is invoked" in { intercept[NoSuchElementException] { Set.empty.head } } }
FeatureSpec
FeatureSpecは、受け入れテストの作成を目的としており、プログラマー以外のプログラマーと協力して受け入れ要件を簡単に記述できるようにします。
import org.scalatest._ class TVSet { private var on: Boolean = false def isOn: Boolean = on def pressPowerButton() { on = !on } } class TVSetSpec extends FeatureSpec with GivenWhenThen { info("As a TV set owner") info("I want to be able to turn the TV on and off") info("So I can watch TV when I want") info("And save energy when I'm not watching TV") feature("TV power button") { scenario("User presses power button when TV is off") { Given("a TV set that is switched off") val tv = new TVSet assert(!tv.isOn) When("the power button is pressed") tv.pressPowerButton() Then("the TV should switch on") assert(tv.isOn) } scenario("User presses power button when TV is on") { Given("a TV set that is switched on") val tv = new TVSet tv.pressPowerButton() assert(tv.isOn) When("the power button is pressed") tv.pressPowerButton() Then("the TV should switch off") assert(!tv.isOn) } } }
ファンスイート
FunSuiteは、以前xUnitを使用していたチームを対象としています。このスタイルを使用すると、Scalatestを快適に切り替えてBDDを活用できます。 使用例:
import org.scalatest.FunSuite class SetSuite extends FunSuite { test("An empty Set should have size 0") { assert(Set.empty.size == 0) } test("Invoking head on an empty Set should produce NoSuchElementException") { intercept[NoSuchElementException] { Set.empty.head } } }
ファンペック
Scalatestの著者は、以前にRSpec for Rubyのようなツールを使用していた人にFunSpecを使用することを提案
import org.scalatest.FunSpec class SetSpec extends FunSpec { describe("A Set") { describe("when empty") { it("should have size 0") { assert(Set.empty.size == 0) } it("should produce NoSuchElementException when head is invoked") { intercept[NoSuchElementException] { Set.empty.head } } } } }
ワードセペック
また、specsおよびspecs2のユーザーに対して、scalatestの作成者は、仕様からscalatestにテストを移植する最も自然な方法であると主張するWordSpec特性の使用を提案しています。
import org.scalatest.WordSpec class SetSpec extends WordSpec { "A Set" when { "empty" should { "have size 0" in { assert(Set.empty.size == 0) } "produce NoSuchElementException when head is invoked" in { intercept[NoSuchElementException] { Set.empty.head } } } } }
FlatSpecの各テストのタイトルは、テスト対象の動作を説明する文で、サブジェクト、キーワードはmustまたはcan、および文の終わりで構成されている必要があります。 見出しが単語inに続き、テストの本文が中括弧で囲まれた後。 完全なテスト例は次のとおりです。
import collection.mutable.Stack import org.scalatest._ class StackSpec extends FlatSpec { "A Stack" should "pop values in last-in-first-out order" in { val stack = new Stack[Int] stack.push(1) stack.push(2) assert(stack.pop() == 2) assert(stack.pop() == 1) } it should "throw NoSuchElementException if an empty stack is popped" in { val emptyStack = new Stack[String] intercept[NoSuchElementException] { emptyStack.pop() } } }
アサーション
各スタイルでは、デフォルトで3つの品揃えが利用できます。
- ルーチンチェックのアサート
- assertResultは、受信した結果と予想される結果が一致するかどうかを確認します
- インターセプトして、メソッドが予期される例外をスローすることを確認します
Scalatestは、predefで定義されたメソッドを非表示にし、標準のAssertionErrorの代わりにTestFailedExceptionをスローするアサートメソッドを定義します。 ただし、assertメソッドは、期待される結果と実際の結果を区別しません。 この区別は、assertResultメソッドを使用して行うことができます。
val a = 5 val b = 2 assertResult(2) { a - b }
この場合、実際の結果が期待される結果と一致しない場合、TestFailedExceptionのメッセージは「Expected 2、but got 3.」になります。
インターセプトメソッドを使用すると、予期される例外をテストできます。
val s = "hi" intercept[IndexOutOfBoundsException] { s.charAt(-1) }
キャッチした例外を返すため、この例外に追加されたメッセージやその他の情報を確認するためにも使用できます。
intercept[IndexOutOfBoundsException](s charAt -1).getMessage should be == "..."
マッチャー
前の例では、beという語の使用を確認できます。 scalatestでは、これは、Matchers mixinをテストを実装するクラスに接続する場合に使用できるキーワードの1つでもあります。 scalatestはDSLの自然言語に非常に近いため、この見出しの下にある追加のコードはほとんどまたはまったく説明なしで提供されます。
この特性を使用すると、自然言語により近い仕様を作成できます。
平等
4 must equal(4) "foo" must equal("foo") List("foo", "bar", "baz") must equal(List("foo", "bar", "baz")) (1, "foo") must equal((1, "foo"))
オブジェクトサイズ、オブジェクト長
"foo" must have length (3) List(1, 2, 3, 4) must have length (4) Array('A', 'B') must have length (2) List(1, 2, 3, 4) must have size (4) Array('A', 'B') must have size (2)
ラインチェック
"foobarbaz" must startWith("foo") "foobarbaz" must endWith("baz") "foobarbaz" must include("bar") "foobarbaz" must startWith regex ("f[o]+") "foobarbaz" must endWith regex ("[ba]{2}z") "foobarbaz" must include regex ("foo[\\w]{3}baz") "foobarbaz" must fullyMatch regex ("\\w{1}oobarbaz")
番号チェック
7 must be < (8) 7 must be > (0) 6 must be <= (7) 7 must be >= (6) 13.43 must equal(13.43) 13.43 must be(13.4 plusOrMinus 0.4)
ブールプロパティの確認
List[Int]() must be('empty) // list.isEmpty new File("/tmp") must be('directory) // file.isDirectory
コレクション
List(1, 2, 3, 4) must contain(2) Array("foo", "bar", "baz") must contain("bar") var users = Map(1 -> "Joe", 2 -> "Lisa", 3 -> "Dr. Evil") users must contain key (2) users must contain value ("Dr. Evil")
クラスのプロパティ
case class Recipe(name: String, ingredients: List[String], bakingMinutes: Int) val cookieRecipe = Recipe("cookieRecipe", List("Flour", "Sugar", "Eggs", "Love"), 30) cookieRecipe must have( 'name("cookieRecipe"), 'ingredients(List("Flour", "Sugar", "Eggs", "Love")), 'bakingMinutes(30) )
チェックとブール関数のリンク
また、チェックは論理関数および/または論理関数を使用して接続できますが、括弧を使用することを忘れないことが重要です。そのため、サンプルユーザーはサイズ(3)でキー(3)を含む必要があります。
users must (have size (3) and contain key (3)) users must (contain value ("Mr. X") or contain value ("Joe"))
この記事では、モックオブジェクトの使用やSeleniumの使用など、このすばらしいフレームワークの多くの機能についてはまだ検討していませんが、示されている機能のみを使用しても、読みやすく、仕様に表現力の点で可能な限り近いテストを書くことができますコード。
www.scalatest.org-プロジェクトサイト