模拟一个继承的最终方法

时间:2016-06-08 20:18:08

标签: java junit mockito

我有两个班级:

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的刚性,因此上面的继承更改不是可接受的解决方案。如何模拟对超类'方法的调用?

2 个答案:

答案 0 :(得分:4)

来自Mockito's FAQ

  

Mockito有哪些限制?
  [...]

     
      
  • 无法模拟最终方法 - 它们的实际行为在没有任何异常的情况下执行。 Mockito不能警告你嘲笑最终方法,所以请保持警惕。
  •   
     

[...]

为此,您需要PowerMock之类的扩展程序。有关工作示例,请参阅this question。整个说明可以在PowerMock's documentation

中找到

答案 1 :(得分:0)

不幸的是你无法模拟最终方法。但是一句警告:转向 PowerMock 并不是解决这个问题的答案。恰恰相反:转向PowerMock意味着进入一个不经过精心准备就不应进入的领域。

PowerMock操纵您的字节代码,以允许您覆盖最终或静态方法。这意味着它会让你遇到各种各样奇怪和怪异的问题;经常没有充分的理由;但很有可能浪费大量时间寻找与您的测试代码无关的“错误”。 PowerMock的另一个大问题是它使大多数“覆盖”框架变得无用(因为那些框架也操纵字节码......)

所以在你的情况下:实际上,将该方法设为最终是一个很好的设计。因为这强调了Open/closed principle。因此,从概念上讲,有两种方法可以“修复”这个:

a)您允许依赖注入该“config”对象(例如,通过提供受“构建”的受保护构造函数)

b)你记得FCoI并且完全避免做基类/子类的事情