質問には2つの部分があります。中間状態を格納するためのvarsの使用と、失敗した場合の例の停止です。
1-変数の使用
可変仕様を使用する場合、varsを使用する代わりの方法がいくつかあります。
lazy vals
プロセスのステップを表すために使用できます。
object DatabaseSpec extends mutable.Specification {
sequential
"The Data Access Object" should {
lazy val id1 = database.save(Entity(1))
lazy val loaded = database.load(id1)
lazy val list = database.list
"save an object" >> { id1 === 1 }
"load one object" >> { loaded.id === id1 }
"list all objects" >> { list === Seq(Entity(id1)) }
}
object database {
def save(e: Entity) = e.id
def load(id: Int) = Entity(id)
def list = Seq(Entity(1))
}
case class Entity(id: Int)
}
これらの値は遅延しているため、例が実行されたときにのみ呼び出されます。
現在の仕様の構造を変更する準備ができている場合は、最新の1.12.3-SNAPSHOTを使用して、これらすべての小さな期待を1つの例にグループ化することもできます。
"The Data Access Object provides a save/load/list api to the database" >> {
lazy val id1 = database.save(Entity(1))
lazy val loaded = database.load(id1)
lazy val list = database.list
"an object can be saved" ==> { id1 === 1 }
"an object can be loaded" ==> { loaded.id === id1 }
"the list of all objects can be retrieved" ==> {
list === Seq(Entity(id1))
}
}
これらの期待のいずれかが失敗した場合、残りは実行されず、次のような失敗メッセージが表示されます。
x The Data Access Object provides a save/load/list api to the database
an object can not be saved because '1' is not equal to '2' (DatabaseSpec.scala:16)
2つの小さな改善が必要となる別の可能性は、Given / When / ThenGiven
の方法で仕様を記述し、内部とWhen
ステップで「スローされた」期待を使用することです。ユーザーガイドでわかるように、Given/When/Then
手順は文字列からデータを抽出し、入力された情報を次の情報に渡しますGiven/When/Then
。
import org.specs2._
import specification._
import matcher.ThrownExpectations
class DatabaseSpec extends Specification with ThrownExpectations { def is =
"The Data Access Object should"^
"save an object" ^ save^
"load one object" ^ load^
"list all objects" ^ list^
end
val save: Given[Int] = groupAs(".*") and { (s: String) =>
database.save(Entity(1)) === 1
1
}
val load: When[Int, Int] = groupAs(".*") and { (id: Int) => (s: String) =>
val e = database.load(id)
e.id === 1
e.id
}
val list: Then[Int] = groupAs(".*") then { (id: Int) => (s: String) =>
val es = database.list
es must have size(1)
es.head.id === id
}
}
私がやろうとしている改善点は次のとおりです。
- 失敗の例外をキャッチして、エラーではなく失敗として報告します
groupAs(".*") and
文字列の説明から抽出するものがない場合に使用する必要がなくなります。
その場合、次のように書くだけで十分です。
val save: Given[Int] = groupAs(".*") and { (s: String) =>
database.save(Entity(1)) === 1
1
}
もう1つの可能性は、直接書き込みを許可することです。
val save: Given[Int] = groupAs(".*") and { (s: String) =>
database.save(Entity(1)) === 1
}
オブジェクトにはすでにタイプの値が含まれているため、Given[T]
からオブジェクトを作成できます。これは「Given」になります。String => MatchResult[T]
MatchResult[T]
T
2-失敗した例の後で実行を停止します
暗黙のWhenFail
Around
コンテキストを使用することは、確かにあなたが望むことを行うための最良の方法です(G / W / Tの例の上に示されているような期待の説明に従わない限り)。
に注意してくださいstep(stepOnFail = true)
並行例の前のブロックの1つの例が失敗したstep(stepOnFail = true)
場合、次の例を中断することによって機能します。ただし、を使用している場合、その前のブロックは1つの例に限定されます。したがって、あなたが見ているもの。実際、これはバグであり、シーケンシャルを使用しているかどうかに関係なく、残りのすべての例を実行するべきではないと思います。ですから、今週の終わりに予定されている修正にご期待ください。sequential