使用Mockito从链式方法捕获参数

时间:2015-04-07 20:32:20

标签: java unit-testing testing mockito

我正在使用Mockito为现有课程编写一些Java单元测试。但是,我无法提取这个类的对象作为嵌套调用的一部分调用方法的参数。

示例:

public class SomeClass {

  public SomeClass() {
    //...
  }

  public someMethod(Foo foo) {
    // Bar bar = ...
    someOtherMethod(bar);
  }

  private someOtherMethod(Bar bar) {
    //...
  }
}

我想捕获someOtherMethod()的参数并验证bar是否应该是什么。我可以使用ArgumentCaptor或Mockito中的其他功能吗?

3 个答案:

答案 0 :(得分:2)

模拟someOtherMethod不太可能为您提供有用的结果。 someMethod是您公开API的一部分,但someOtherMethod不是;一般来说,测试合同很重要(someMethod的返回值和副作用),但它是一个反模式来测试实现(someMethod调用的私有方法)。

  • 理想情况下,只需测试someMethod的结果和副作用,并将其实现视为黑盒子。你可能甚至不需要使用Mockito。这是测试驱动开发的最纯粹形式:它可以让您重构someMethod,可能完全省略对someOtherMethod的调用或缓存结果(等)而无需编辑测试。
  • 如果someOtherMethod调用外部服务,请将其设置为SomeClass实例上的可访问或可设置字段,并改为模拟该服务。 与其他服务的互动可以合理地视为一般合同的一部分;这就是Mockito的设计理念。
  • 如果someOtherMethod足够独立,您希望单独测试someMethod,请考虑将其设为包私有或受保护。这样你可以在测试中使用虚拟实现覆盖它,也可能在代码中的其他位置覆盖它 - 毕竟,它现在已成为someMethod合同的一部分,对吧?如果它是大的或不透明的,你也可以考虑将它作为一个单独的可模拟类。

另请参阅Programmers.SE中的"How do I unit test private methods?"或StackOverflow上的"How to use Mockito when we cannot pass a mock object to an instance of a class"

答案 1 :(得分:0)

一个选项是使用存储这些参数的类重写SomeClass,并使它们可供您进行验证。优雅的选项是custom argument matchers

答案 2 :(得分:0)

@Spy
private SomeClass someClassSpy;

@Captor
private ArgumentCaptor<Bar> barCaptor;

...

verify(someClassSpy).someOtherMethod(barCaptor.capture());
Bar bar = barCaptor.getValue();
assertThat(bar, is(...));