我相信这现在是一个很常见的问题,但我真的无法解决我在嘲笑私有方法时遇到的这个问题,该方法在内部调用另一个方法并返回一个集合。我正在测试的类有一个公共方法,它调用私有方法来获取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;
}
测试类别-:
因此,为了测试公共方法"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.
上面调用了私有方法,该方法又试图调用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.
上面的mocking再次调用了callWrapperMethod()的实际实现,并在其中中断。如何防止调用包装器方法的实际实现?
帮助我的答案很少-:
Mockito:如何模拟在另一个方法中调用的方法
使用mockito 测试私有方法
[更新]-:正如我所做的建议-:
PowerMockito.doReturn(list).when(spy1).callWrapperMethod(); // This returns me demo list successfully.
但现在,当我从PowerMockito调用private方法时,控件进入invokePrivate方法,并再次尝试调用原始的callWrapperMethod,而不是间谍版本的返回列表。
我建议不要这样做。您的私有方法应该而不是使用静态方法检索singleton工厂对象。
静态的东西打破了"轻松"的嘲讽;强迫你使用"权力"嘲讽;从而产生比解决更多的问题。
更改代码以使用依赖项注入。这样做:
class YourClass {
private final Factory factory;
public YourClass() {
this(Factory.getInstance(); }
YourClass(Factory theFactory) {
this.factory = theFactory;
...
这将允许您在单元测试中使用第二个构造函数;为您的类提供一个(易于模拟的)工厂对象。从而消除了对PowerMock的全部需求。
长话短说-当代码很难测试时;更改代码;而不是测试。副作用是,您正在提高代码的质量,因为您放松了对该singleton对象的硬依赖。
为了完整起见:我还建议避免"违反"德米特定律(http://en.wikipedia.org/wiki/Law_of_Demeter):如果您的类需要包装器;那么它应该包含一个包装器对象;如果它需要那家工厂;那么它应该包含一个工厂对象。但你不应该拿着一个物体。。。从那里检索另一个对象,在第二个对象上运行一些东西。正如你所看到的,这样做恰恰会导致你所面临的那种问题。