我有两个班级:
public class BaseClass <T> {
private final T config;
...
@NotNull
public final T getConfig() {
return config;
}
}
public class DerivedClass extends BaseClass<MyConfig> {
...
}
测试:
...
MyConfig myConfig = mock(MyConfig.class);
DerivedClass child = mock(DerivedClass.class);
when(child.getConfig()).thenReturn(myConfig); // this line generates the error
我收到getConfig()
返回null的错误,而不是myConfig
。我有相同的模拟对象的其他方法调用与when / return模式一样工作,所以我玩了多态。当我删除方法的最终限制并在派生类中重写它(只是调用超级版本)时,模拟工作正常。
对于测试,我不想重新设计产品代码并降低API的刚性,因此上面的继承更改不是可接受的解决方案。如何模拟对超类'方法的调用?
答案 0 :(得分:4)
Mockito有哪些限制?
[...]
- 无法模拟最终方法 - 它们的实际行为在没有任何异常的情况下执行。 Mockito不能警告你嘲笑最终方法,所以请保持警惕。
[...]
为此,您需要PowerMock之类的扩展程序。有关工作示例,请参阅this question。整个说明可以在PowerMock's documentation
中找到答案 1 :(得分:0)
不幸的是你无法模拟最终方法。但是一句警告:转向 PowerMock 并不是解决这个问题的答案。恰恰相反:转向PowerMock意味着进入一个不经过精心准备就不应进入的领域。
PowerMock操纵您的字节代码,以允许您覆盖最终或静态方法。这意味着它会让你遇到各种各样奇怪和怪异的问题;经常没有充分的理由;但很有可能浪费大量时间寻找与您的测试代码无关的“错误”。 PowerMock的另一个大问题是它使大多数“覆盖”框架变得无用(因为那些框架也操纵字节码......)
所以在你的情况下:实际上,将该方法设为最终是一个很好的设计。因为这强调了Open/closed principle。因此,从概念上讲,有两种方法可以“修复”这个:
a)您允许依赖注入该“config”对象(例如,通过提供受“构建”的受保护构造函数)
b)你记得FCoI并且完全避免做基类/子类的事情