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

Mr.*_*ful 5 java junit unit-testing mockito powermock

我确信这是一个很常见的问题,但我真的无法摆脱这个问题,因为我在模拟私有方法时会在内部调用另一个方法并返回一个集合。我正在测试的类有一个公共方法,它调用私有方法来获取 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;
}
Run Code Online (Sandbox Code Playgroud)

测试类-:

因此,为了测试公共方法“method1”,我使用 PowerMockito 创建一个间谍来监视私有方法并返回演示列表。

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.
Run Code Online (Sandbox Code Playgroud)

上面调用了私有方法,该方法又尝试调用位于不同工件中的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.
Run Code Online (Sandbox Code Playgroud)

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

很少有答案对我有帮助:

Mockito:如何模拟在另一个方法中调用的方法

使用mockito测试私有方法

[更新]-:按照我所做的建议-:

PowerMockito.doReturn(list).when(spy1).callWrapperMethod(); // This returns me demo list successfully.
Run Code Online (Sandbox Code Playgroud)

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

Gho*_*ica 3

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

静态的东西打破了“简单”的嘲笑;强迫你使用“权力”嘲讽;因此,产生的问题比解决的问题还要多。

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

class YourClass {
  private final Factory factory;

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

  YourClass(Factory theFactory) {
     this.factory = theFactory;
  ...
Run Code Online (Sandbox Code Playgroud)

这将允许您在单元测试中使用第二个构造函数;为您的类提供一个(容易模拟的)工厂对象。这样您就不再需要 PowerMock。

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

为了完整起见:我还建议避免“违反”德米特法则(http://en.wikipedia.org/wiki/Law_of_Demeter):如果你的类需要包装器;那么它应该保存一个包装对象;如果需要那个工厂;那么它应该保存一个工厂对象。但是你不应该持有一个对象......从那里检索另一个对象,在第二个对象上运行某些东西。正如您所看到的 - 这样做会导致您所面临的问题。