Kaj*_*nus 5 integration-testing scala specs2
有没有一些首选的方法来设计Specs2测试,有很多测试依赖于以前的测试结果?
下面,您将找到我当前的测试套件.我不喜欢var测试片段之间的s.然而,它们是"需要的",因为一些测试生成后续测试重用的ID号.
我是否可以将ID号存储在Specs2 Context中,或者创建一个包含所有可变状态的单独Object?并且只在测试对象中放置测试片段?还是有一些更好的方法?
如果测试失败,我想取消相同深度的剩余测试.我可以让测试片段相互依赖吗?(我知道我可以在一个测试片段中取消剩余的匹配器(通过使用可变测试,或通过orSkip),但是取消整个片段呢?)
.
object DatabaseSpec extends Specification {
sequential
"The Data Access Object" should {
var someId = "" // These var:s feels error prone, is there a better way?
"save an object" >> {
someId = database.save(something)
someId must_!= ""
// I'd like to cancel the remaining tests, below, at this "depth",
// if this test fragmen fails. Can I do that?
// (That is, cancel "load one object", "list all objects", etc, below.)
}
"load one object" >> {
anObject = database.load(someId)
anObject.id must_== someId
}
"list all objects" >> {
objs = database.listAll()
objs.find(_.id == someId) must beSome
}
var anotherId = ""
...more tests that create another object, and
...use both `someId` and `anotherId`...
var aThirdId = ""
...tests that use `someId`, `anotherId` and `aThirdId...
}
"The Data Access Object can also" >> {
...more tests...
}
}
Run Code Online (Sandbox Code Playgroud)
您的问题有两部分:使用变量来存储中间状态,并在示例失败时停止示例。
1 - 使用变量
使用可变规范时,有一些替代方法可以替代变量。
您可以使用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)
}
Run Code Online (Sandbox Code Playgroud)
由于这些值是惰性的,因此只有在执行示例时才会调用它们。
如果您准备好更改当前规范的结构,您还可以使用最新的 1.12.3-SNAPSHOT 并将所有这些小期望分组到一个示例中:
"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))
}
}
Run Code Online (Sandbox Code Playgroud)
如果这些期望中的任何一个失败,那么其余的将不会被执行,并且您将收到如下失败消息:
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)
Run Code Online (Sandbox Code Playgroud)
另一种可能需要进行两项小改进,即使用“ Given/When/Then”方式编写规范,但在内部Given和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
}
}
Run Code Online (Sandbox Code Playgroud)
我要做的改进是:
groupAs(".*") and当无法从字符串描述中提取任何内容时,无需使用。在这种情况下,编写以下内容就足够了:
val save: Given[Int] = groupAs(".*") and { (s: String) =>
database.save(Entity(1)) === 1
1
}
Run Code Online (Sandbox Code Playgroud)
另一种可能性是允许直接写入:
val save: Given[Int] = groupAs(".*") and { (s: String) =>
database.save(Entity(1)) === 1
}
Run Code Online (Sandbox Code Playgroud)
其中Given[T]可以从 a 创建一个对象,String => MatchResult[T]因为该MatchResult[T]对象已经包含类型 的值T,该值将成为“Given”。
2 - 失败示例后停止执行
使用隐式WhenFail Around上下文当然是完成您想要的操作的最佳方式(除非您遵循 G/W/T 示例上方所示的期望描述)。
注意事项step(stepOnFail = true)
如果前一并发示例块中的step(stepOnFail = true)一个示例失败,则其工作原理是中断以下示例。但是,当您使用 时,前一个块仅限于一个示例。这就是你所看到的。实际上,我认为这是一个错误,无论您是否使用顺序,所有剩余的示例都不应该执行。因此,请继续关注本周末即将推出的修复程序。sequential
| 归档时间: |
|
| 查看次数: |
1650 次 |
| 最近记录: |