【问题标题】:mockito : mock method call with parameters by reflectionmockito :通过反射模拟带参数的方法调用
【发布时间】:2014-11-24 16:43:42
【问题描述】:

我正在使用 mockito 并使用 java6 和 spring 进行开发。

我正在为一些开发人员开发一个测试 API,并且我提出了一些模拟对象和方法的方法(这是一个遗留代码......)。 现在,我想用 mockito 替换所有这些东西,但我总是提出一个测试 API。所以,我开发了一些使用 mockito 的方法。

我有一个带有两个参数(字符串)的旧方法。第一个参数是模拟的服务 id 及其带有参数的方法。第二个参数是返回的对象。 示例:

mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject);

现在,我想使用 mock、when 和 thenReturn mockito 方法,但我不知道如何... 也许使用反射但使用“何时”方法是不可能的,因为mockito需要有效的方法。 我怎样才能做到这一点 ?谢谢。

【问题讨论】:

  • 我不明白为什么你不能直接在“真实的东西”上使用mockito?是你要模拟的类(或任何方法)final
  • 你问如何解析“myServiceId.myMethod(String, Integer)”?如果是这样,恐怕这不太可能。
  • 我认为最好有一个更具体的例子来说明你想在这里测试什么。一个完整的测试方法,完整的场景或某事。它是在模拟自制的模拟框架吗?
  • 我不能直接使用 mockito。我正在研究一个框架。这是一个遗留代码......我必须为开发人员隐藏 mockito,因为它们不需要管理版本等。我必须解析“myServiceId.myMethod(String, Integer)”并模拟 bean myServiceId,最后返回“myMethod” ... 例如:我有一个 bean“MyBean1”,在里面有另一个 bean“MyBean2”。在“MyBean1”测试类中,我必须用这个方法模拟“MyBean2”:mockReturnObject("myServiceId.myMethod(String, Integer)", myReturnedObject);在里面,我想使用mockito。就这样。谢谢。
  • 我不想在应用程序中模拟某些东西。我正在开发一个框架,开发人员不能直接使用 mockito。

标签: java spring unit-testing mockito


【解决方案1】:

这是一个坏主意:您试图重新实现 Mockito 已经提供的一些系统,同时失去了 Mockito 提供的许多功能。但是,有一种方法可以使这项工作发挥作用,但有一些困难。关键是写一个custom Answer,将其设为default answer,用于mock,然后使用InvocationOnMock比较你的对象、方法名和方法参数类型。

public class ReflectiveMockAnswer implements Answer<Object> {
  @Override public Object answer(InvocationOnMock invocation) {
    // Assume you've successfully parsed each String into a StubbedResponse, with
    // Object target, String method, String[] argTypes, and Object returnValue.
    // A Set would beat a for-loop here, should you need to optimize.
    for (StubbedResponse stubbedResponse : allStubbedResponses) {
      if (stubbedResponse.target == invocation.getMock()
          && stubbedResponse.method.equals(invocation.getMethod().getName())
          && stringArraysEqual(stubbedResponse.argTypes,
              typeNamesFrom(invocation.getMethod().getParameterTypes())) {
        return stubbedResponse.returnValue;
      }
    }
    throw new RuntimeException("Unstubbed method called.");
  }
}

// Later...
Object yourMockObject = Mockito.mock(classToMock, new ReflectiveMockAnswer());

此时,您已经在完整版 Mockito 的基础上实现了 Mockito 的简化版。您还需要:

  • 将字符串解析为 StubbedResponse,可能使用正则表达式
  • 按名称标识被测 bean 中的字段
  • 在被测 bean 有机会与之交互之前,用上述创建的适当类的模拟替换该字段

...并承认此解决方案无法处理:

  • 验证
  • 任何类型的参数匹配,包括基本的“等于”匹配
  • 参数类型中的名称冲突(com.foo.SomeClass 与 com.bar.SomeClass)
  • 重复呼叫 (thenReturn(1, 2, 3).thenThrow(new RuntimeException()))

...而不能处理:

  • 代码搜索工具:您只能通过搜索字符串来判断哪些方法被模拟,而不能像 Mockito 那样使用 Eclipse 中的“查找引用”之类的工具
  • 编译时检查和自动重构工具:如果字段名称、方法名称或参数发生更改,您的测试将在运行时中断; Mockito 没有这个问题
  • 最终方法:Mockito 不能,所以你也不能

除非这是一个“稻草人”或非常临时的解决方案,否则我强烈建议将 Mockito 直接引入您的测试用例,一次一个测试。

【讨论】:

    猜你喜欢
    • 2016-05-26
    • 2011-01-26
    • 1970-01-01
    • 2016-04-25
    • 2014-04-20
    • 1970-01-01
    • 2016-04-07
    • 2013-07-18
    • 2010-09-16
    相关资源
    最近更新 更多