为什么Specs2以随机顺序运行这些"顺序"测试?

Kaj*_*nus 3 integration-testing scala specs2 playframework-2.1

有一个旧的数据库测试套件,我正在尝试从Specs迁移到Specs2.但是,Specs2以一种奇怪的顺序运行测试(从我的角度来看),它打破了测试,因为它们改变了数据库状态,并运行了两次特定的代码.

在下面找到测试的简化版本.据我了解,试验应该按以下顺序执行:(因为我指定的顺序): ,,
! 222 然而,实际发生的事情,是他们在这个顺序执行会:,,! 333! 444

! 333! 222! 444

以下是测试:

object IncludedSpec extends Specification {
  sequential
  println("sssstart")

  "IncludedSpec" should {

    println("..222")
    "context free block" >> {
      println("....! 222 the first test")
      1 === 1
    }

    var variableN = 0

    "block with context" >> {
      println("....333")
      "using one variable" >> {
        println("......! 333 doing some tests and setting variableN")
        variableN = 123
      }

      println("....444")
      "using it again" >> {
        println("......! 444 testing variableN")
        variableN === 123
      }
      println("....555")
    }
  }

  println("eeeend")
}
Run Code Online (Sandbox Code Playgroud)

这是所有println输出:

sssstart
eeeend
sssstart
eeeend
..222
....333
......! 333 doing some tests and setting variableN
....444
....555
....! 222 the first test
......! 444 testing variableN
Run Code Online (Sandbox Code Playgroud)

还有我的两个问题:

  1. 为什么不! 222先执行?

  2. sssstart eeeend输出两次怎么可能?规范是一个对象,不会创建两次?

奇怪的是,如果我从测试中删除副作用 - 也就是说,删除变量N并用ok- 替换测试体- 测试以正确的顺序运行.

版本详细信息:我正在使用Paly Framework 2.1-SNAPSHOT(2012年10月28日版本203df0e)和Scala 2.10.0-RC1运行这些测试.我认为与Play捆绑的Specs2版本是版本1.12,因为该inline方法可用,并且它是在1.12(-SNAPSHOT)中添加的,请参阅https://github.com/etorreborre/specs2/issues/87并且之后没有规格2版本.

(哦,如果你认为我应该完全重写测试,那么请看看这个问题:如何设计一个Specs2数据库测试,相互依赖的测试?)

Eri*_*ric 10

最初,在specs2中,您可以创建以下内容:

1 - 一个例子in:"this is an example" in { 1 must_== 1 }

2 - 一个例子>>:"this is an example" >> { 1 must_== 1 }

3 - 一组示例 >>

"this system should" >> {
  "do something" >> ok
  "do something else" >> ok
}
Run Code Online (Sandbox Code Playgroud)

重要的是,in仅为示例保留,并接受任何可以转换为Result.另一方面>>,可以用于示例和示例组(以具有统一的嵌套样式),因此它接受类型Example或的值Result.

现在,当您想要执行以下操作时,事情变得有点复杂:

1 - 用于foreach创建一组示例

"this group has 5 examples" in {
  (1 to 5) foreach { i => "example "+i >> ok }
}
Run Code Online (Sandbox Code Playgroud)

2 - 用于foreach创造一组期望

"this example has 5 expectations" in {
  (1 to 5) foreach { i => i must_== i }
}
Run Code Online (Sandbox Code Playgroud)

麻烦的是,这两个表达式foreach都有类型Unit.但他们正在做两件完全不同的事情!第一个是构建示例,因此需要立即评估此表达式以构建示例Specification.第二个是创建an的主体Example并将在稍后执行(或者如果示例被过滤掉,则可能永远不会执行).有两个东西,使用相同的运算符>>,无法工作.

所以决定>>(block: =>Unit)意味着"这通过副作用建立一组例子",并且in(expectations: =>Unit)意味着"这构建了一个Example可能具有期望的机构,这将是副作用.

现在,当这更好地解释了为什么你看到一个与你的打印语句有关的奇怪订单:

..222
....333
......! 333 doing some tests and setting variableN
....444
....555
Run Code Online (Sandbox Code Playgroud)

首先打印,因为它们包含在类型的块中Unit,被解释为示例组.

而且:

....! 222 the first test
......! 444 testing variableN
Run Code Online (Sandbox Code Playgroud)

因为它们是类型的块,所以它们被打印MatchResult[_],也就是说,它们被认为是例子的主体.

我同意这是令人困惑的,我希望这种解释可以为某些事情带来一些看法.当然,另一个教训是"副作用是偷偷摸摸的,因为他们没有告诉你他们真正在做什么".

所以一般的specs2提示总是以适当的值结束你的块(除非你使用foreach如我上面的例子中所示的构造).例如,ok在您执行变量赋值的块的末尾添加应该可以解决您的问题.