对模拟对象的验证不符合测试用例

时间:2019-02-01 19:37:48

标签: scala mocking mockito mockit-scala

问题:

假设我们有两种不同的服务

class ServiceA(serviceB: ServiceB) {

  def methodA(): String = {
    "methodA called"
    serviceB.methodB()
  }

  def methodA2(): String = {
    "methodA2 called"
    serviceB.methodB()
  }
}

我编写了两个测试方法,并尝试验证methodB是否被调用。当我分别运行两个测试用例时,测试通过。当我运行所有测试方法时,验证为第二次测试给出了错误的结果。 在测试类方面,的Mockito验证记录mock对象上的所有呼叫。我认为在每次测试后,mockito-scala应该重置模拟对象的验证计数

class ServiceATest extends FlatSpec with IdiomaticMockito {
  val serviceB: ServiceB = mock[ServiceB]
  val serviceA: ServiceA = new ServiceA(serviceB)
  "methodA" should "called" in {
    serviceA.methodA()
    serviceB.methodB wasCalled once // Passes
  }
  "methodA2" should "called" in {
    serviceA.methodA2()
    serviceB.methodB wasCalled once // Fail. was 2 times
  }
}

我尝试过使用Mockito-core,它给出了同样的错误。

1 个答案:

答案 0 :(得分:2)

您的serviceAserviceB对象实际上是测试装置,但是您以错误的方式共享它们。使用像您这样的代码,所有测试将共享相同的对象,这意味着测试将通过共享的脏状态相互交互。 ScalaTest支持多种方式为share fixtures。一项所述的清洁器的方式是loan pattern如:

class ServiceATest extends FlatSpec with IdiomaticMockito {

  def withServicesAandBMock(testCode: (ServiceA, ServiceB) => Any) {
    val serviceB: ServiceB = mock[ServiceB]
    val serviceA: ServiceA = new ServiceA(serviceB)
    testCode(serviceA, serviceB)
  }

  "methodA" should "called" in withServicesAandBMock { (serviceA, serviceB) =>
    serviceA.methodA()
    serviceB.methodB wasCalled once // Passes
  }

  "methodA2" should "called" in withServicesAandBMock { (serviceA, serviceB) =>
    serviceA.methodA2()
    serviceB.methodB wasCalled once // now passes as well
  }
}

另外,您可以使用ResetMocksAfterEachTest

class ServiceATest extends FlatSpec with IdiomaticMockito with ResetMocksAfterEachTest {

  val serviceB: ServiceB = mock[ServiceB]
  val serviceA: ServiceA = new ServiceA(serviceB)
  "methodA" should "called" in {
    serviceA.methodA()
    serviceB.methodB wasCalled once // Passes
  }
  "methodA2" should "called" in {
    serviceA.methodA2()
    serviceB.methodB wasCalled once // now passes as well
  }
}

但是恕我直言,这是一种作弊行为