假设我有这个接口和类:
abstract class SomeInterface{
def doSomething : Unit
}
class ClassBeingTested(interface : SomeInterface){
def doSomethingWithInterface : Unit = {
Unit
}
}
请注意,doSomethingWithInterface方法实际上并没有对接口执行任何操作。
我为它创建了一个这样的测试:
import org.specs2.mutable._
import org.specs2.mock._
import org.mockito.Matchers
import org.specs2.specification.Scope
trait TestEnvironment extends Scope with Mockito{
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
}
class ClassBeingTestedSpec extends Specification{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in new TestEnvironment {
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
此测试通过。为什么?我设置错了吗?
当我摆脱范围:
class ClassBeingTestedSpec extends Specification with Mockito{
"The ClassBeingTested" should {
"#doSomethingWithInterface" in {
"calls the doSomething method of the given interface" in {
val interface = mock[SomeInterface]
val test = new ClassBeingTested(interface)
test.doSomethingWithInterface
there was one(interface).doSomething
}
}
}
}
测试按预期失败:
[info] x calls the doSomething method of the given interface
[error] The mock was not called as expected:
[error] Wanted but not invoked:
[error] someInterface.doSomething();
这两种测试有什么区别?为什么第一个应该失败却通过了?这不是Scopes的预期用途吗?
当您将Mockito
特征与另一个特征混合时,您可以创建类似there was one(interface).doSomething
的期望值。如果这样的表达式失败,它只返回Result
,而不会抛出Exception
。然后它会在Scope
中丢失,因为它只是一个特质体内的"纯粹"值。
但是,如果将Mockito
特性混合到mutable.Specification
中,则会在失败时引发异常。这是因为mutable.Specification
类通过混合该特性来指定应该存在ThrownExpectations
。
因此,如果你想创建一个扩展两个Scope
的特性,你可以:
-
从规范内部创建特性,而不是让它扩展Mockito:
class MySpec extends mutable.Specification with Mockito { trait TestEnvironment extends Scope { val interface = mock[SomeInterface] val test = new ClassBeingTested(interface) } ... }
-
创建特性和规范,但在
org.specs2.execute.ThrownExpectations
中混合trait TestEnvironment extends Scope with Mockito with ThrownExpectations { val interface = mock[SomeInterface] val test = new ClassBeingTested(interface) } class MySpec extends mutable.Specification with Mockito { ... }