在下面的测试中,我有一个无效的存根设置。模拟requestBuilder
使用参数"INCORRECT"
进行存根处理,而测试中的类使用"/socket"
调用它。
我在JUnit中使用Mockito的经验告诉我,运行时的调用将导致null
。然而,我看到了一个假阳性。测试通过&requestBuilder
返回模拟request
,即使它是用"/socket"
调用的。
为什么会这样?这与拥有不止一个期望有关吗?如果是这样的话,那么最终的期望是最重要的,并且它应该失败。
class ChannelSpec extends Specification with Mockito with ScalaCheck with ArbitraryValues { def is = s2"""
A Channel must
send an open request to /socket with provided channel name on instantiation $sendToSocket
"""
def sendToSocket = prop{(name: String, key: Key, secret: Secret) =>
val requestBuilder = mock[(String, Seq[Map[String, String]]) => Req]
val request = mock[Req]
val httpRequestor = mock[(Req) => Future[String]]
val result = mock[Future[String]]
val params = Seq(Map("key" -> key.value, "timestamp" -> anyString, "token" -> anyString), Map("channel" -> name))
requestBuilder("INCORRECT", params) returns request
httpRequestor(request) returns result
new Channel(name, key, secret, requestBuilder = requestBuilder, httpRequestor = httpRequestor)
there was one(requestBuilder).apply("INCORRECT", params)
println("expecting " + request)
there was one(httpRequestor).apply(request)
}
虽然我不了解Scala,但我知道anyString
并不像你想象的那样。具体来说,所有Mockito匹配器都会处理副作用,将相关的String对象添加到ArgumentMatcherStorage
中,正如我在本SO答案末尾所描述的那样。
因此,您无法真正将匹配符提取到变量中:
// This is fine, because the parameters are evaluated in order.
takesTwoParameters(eq("A"), eq("B")) returns bar
// Now let's change it a little bit.
val secondParam = eq("SECOND")
val firstParam = eq("FIRST")
// At this point, firstParam == secondParam == null, and the hidden argument
// matcher stack looks like [eq("SECOND"), eq("FIRST")]. That means that your
// stubbing will apply to takesTwoParameters("SECOND", "FIRST"), not
// takesTwoParameters("FIRST", "SECOND")!
takesTwoParameters(firstParam, secondParam)) returns bar
此外,您不能将anyString
嵌套到任意类型中,如Seq或Map;Mockito的参数匹配器旨在匹配整个参数。
您最好的选择是对参数使用argThat
,并创建一个小的Hamcrest匹配器来检查您正在检查的参数是否正确形成。这将使您能够灵活地检查参数是否大致符合您的期望,同时忽略您不关心的值。
我认为这只是一种表现,即在验收规范中,没有异常情况表明预期失败。所以你有:
def test = {
1 === 2
1 === 1
}
那么test
将通过,因为只有最后一个值将被保留为测试结果。您可以通过链接期望来改变这种行为:
def test = {
(1 === 2) and
(1 === 1)
}
或者通过在规范中混合ThrownExpectations
特性:
import org.specs2.Specification
import org.specs2.matcher.ThrownExpectations
import org.specs2.mock.Mockito
class MySpec extends Specification with ThrownExpecations with Mockito {
...
}