使用 PowerMock 和 Mockito 测试对其他工件方法的调用

Using PowerMockito and Mockito to test call to other artifact's method

我确信这是一个很常见的问题,但我真的无法摆脱这个问题,因为我在模拟私有方法时遇到了这个问题,该方法在内部调用另一个方法并且 return 是一个集合。 我正在测试的 Class 有一个 public 方法,它调用私有方法来获取 Collection 对象。我用PowerMock创建了一个私有方法的间谍

public void method1(String s)
{
     Collection<Object> list = invokePrivate()
}

private Collection<Object> invokePrivate()
{
     Wrapper wrapperObj = Factory.getInstance.getWrapper();
     Collection<Object> list = wrapperObj.callWrapperMethod(); // This always calls into real method, instead of mocked version.
     return list;
}

测试Class-:

所以为了测试 public 方法 "method1" 我使用 PowerMockito 创建了一个间谍来监视私有方法和 return 一个演示列表。

MainClass obj = new MainClass();
MainClass spy = PowerMockito.spy(obj);
PowerMockito.when(spy, method(MainClass.class, "inokePrivate"))
                            .thenReturn(list); // demo list which exists as a test class member.

以上调用私有方法,该方法依次尝试调用驻留在不同工件中的 wrapperObj.callWrapperMethod() 并在那里中断,因为它在那里找不到某些实现。 所以我试着模拟 wrapperObj.callWrapperMethod.

WrapperClass wr = new WrapperClass();
WrapperClass spy1 = PowerMockito.spy(wr);
when(spy1.callWrapperMethod()).thenReturn(list) // demo list which exists as a test class member.

上面的模拟再次调用 callWrapperMethod() 的实际实现并在那里中断。 如何防止调用包装器方法的实际实现?

很少有对我有帮助的答案-:

Mockito:How to mock method called inside another method

Testing Private method using mockito

[更新]-:正如我所建议的那样-:

PowerMockito.doReturn(list).when(spy1).callWrapperMethod(); // This returns me demo list successfully.

但是现在当我从 PowerMockito 控件调用私有方法时进入 invokePrivate 方法并再次尝试调用原始 callWrapperMethod 而不是间谍版本的 return 列表。

我建议不要这样做。您的私有方法应该 而不是 使用静态方法检索单例工厂对象。

静态内容中断 "easy" 嘲笑;强迫你使用 "power" 模拟;因此,制造的问题多于解决的问题。

更改您的代码以使用依赖项注入。做这样的事情:

class YourClass {
  private final Factory factory;

  public YourClass() {
     this(Factory.getInstance(); }

  YourClass(Factory theFactory) {
     this.factory = theFactory;
  ...

这将允许您在单元测试中使用第二个构造函数;为您的 class 提供一个(很容易模仿的)工厂对象。因此,您消除了对 PowerMock 的全部需求。

长话短说 - 当代码难以测试时;更改代码;而不是测试。作为副作用,您正在提高代码的质量 - 因为您失去了对该单例对象的硬依赖。

并且为了完整起见:我还建议避免 "breaking" 得墨忒耳法则 (http://en.wikipedia.org/wiki/Law_of_Demeter):如果您的 class 需要包装器;那么它应该包含一个包装器对象;如果它需要那个工厂;那么它应该包含一个工厂对象。但是你不应该持有一个对象......从那里检索另一个对象,到第二个对象上的 运行 东西。如您所见 - 这样做会导致您面临的问题。