使用 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 需要包装器;那么它应该包含一个包装器对象;如果它需要那个工厂;那么它应该包含一个工厂对象。但是你不应该持有一个对象......从那里检索另一个对象,到第二个对象上的 运行 东西。如您所见 - 这样做会导致您面临的问题。
我确信这是一个很常见的问题,但我真的无法摆脱这个问题,因为我在模拟私有方法时遇到了这个问题,该方法在内部调用另一个方法并且 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 需要包装器;那么它应该包含一个包装器对象;如果它需要那个工厂;那么它应该包含一个工厂对象。但是你不应该持有一个对象......从那里检索另一个对象,到第二个对象上的 运行 东西。如您所见 - 这样做会导致您面临的问题。