2016-06-08 85 views
2

我有两个类:模拟继承的最终方法

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。我还有其他方法调用相同的模拟对象与预期的时间/返回模式,所以我玩弄了多态性。当我删除了方法的最后限制并在派生类中覆盖它(只是调用超级版本)时,模拟工作正常。

我不想为产品测试重新设计产品代码并降低API的刚性,因此上面的继承更改不是可接受的解决方案。我怎样才能调出超类的方法?

+0

“模拟继承的方法” - 你总是可以做出关于其出身粗鲁的评论,但是这不会是政治上正确的(对不起,couldn”不要抵制标题:-) –

回答

4

Mockito's FAQ

什么的的Mockito的限制?
[...]

  • 不能嘲笑最后的方法 - 没有任何异常,执行他们的实际行为。 Mockito无法警告你嘲笑最后的方法,所以要提高警惕。

[...]

对于这一点,你需要像PowerMock的延伸。有关工作示例,请参阅this question。一个完整的描述可以在PowerMock's documentation

+1

提示:至少应该提到** PowerMock **有很多缺点。我绝不会把它推荐给另一个没有良好剂量的人,“通常你根本不应该使用它”。 – GhostCat

0

不幸的是,你不能嘲笑最后的方法。但一个警告:转向PowerMock是不是这个问题的答案。相反:转向PowerMock意味着进入一个不应该在没有经过精心准备的情况下进入的领域。

PowerMock操纵你的字节码,允许你重载最终或静态方法。这意味着它会让你接触到各种奇怪而奇怪的问题;往往没有理由;但是很可能会浪费大量时间来寻找与您的代码无关的“bug”。 PowerMock的另一个大问题是,它使大多数“覆盖”框架无用(因为这些框架还操纵字节码......)

所以在你的情况下:实际上,使该方法最终成为好设计。因为这强调了Open/closed principle。所以,从概念上分,有两个选项“修理”这样的:

a)您提供了一个受保护的构造采取“配置”允许该“配置”对象(例如依赖注入)

二)你还记得FCoI,避免做基类/子类的事完全

+0

Bertrand Meyer(“开放 - 封闭”原则的创造者)写道(我现在似乎无法找到它,对不起)对于程序设计语言(如C++),默认情况下方法不可覆盖(非虚拟)或者甚至允许方法是“最终”的,因为这会阻止OCP的应用。所以,虽然它*是一个很好的设计,使得方法和类成为final,但它完全不强调OCP。相反,它强调GoF的“偏好构成而非继承”原则。 –

+0

如果您无意阻止子类覆盖某种方法,您如何关闭**修改**的类? OCP的典型用例是当你有一个抽象基类提供一个或多个要调用的最终方法时......它们自己调用抽象方法。如果这些方法不是最终的,你可以在子类上改变这种行为。 – GhostCat

+0

事实上,不,在OCP(正如Meyer的书和[Robert Martin的文章](https://www.cs.duke.edu/courses/fall07/cps108/papers/ocp.pdf)中所描述的) “封闭”仅仅是一种已投入生产的产品,因此不应该因违反客户代码而受到修改。请注意这是作者所说的;我发现这个原则完全错误和过时。在OCP作者看来,一个类应该保持“可扩展性”,也就是说,它不应该被声明为final,也不应该将它的任何非'private'方法声明为'final'。 –