【问题标题】:Verification on mock object not respect to test case对模拟对象的验证不尊重测试用例
【发布时间】:2019-02-01 19:37:47
【问题描述】:

问题:

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

class ServiceA(serviceB: ServiceB) {

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

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

我编写了两个测试方法并尝试验证是否调用了methodB。当我分别运行两个测试用例时,测试通过了。当我运行所有测试方法时,验证给出了第二次测试的错误结果。 在测试类上下文中,mockito-verification 记录对模拟对象的所有调用。我认为 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,它给出了同样的错误。

【问题讨论】:

    标签: scala mocking mockito


    【解决方案1】:

    您的 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
      }
    }
    

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

    【讨论】:

    • 解决它的标准方法是使用内部特征github.com/mockito/mockito-scala/issues/74
    • @mstzn,这种“内在特征”解决方案是相同的贷款模式,但结构略有不同。我认为你喜欢哪种方式取决于品味而不是真正的实际优点。我还建议您阅读已经引用的 ScalaTest article 以查看在其他情况下可能有用的其他选项。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多