Mockito如何嘲笑只有超类方法的调用

我在一些testing中使用Mockito。

我有以下类:

class BaseService { public void save() {...} } public Childservice extends BaseService { public void save(){ //some code super.save(); } } 

我只想嘲笑super.save的第二个调用( super.save )。 第一个电话必须叫真正的方法。 有没有办法做到这一点?

不,Mockito不支持这个。

这可能不是你正在寻找的答案,但是你所看到的是不应用devise原则的一个症状:

喜欢inheritance的构成

如果你提取一个战略,而不是扩展一个超类,问题就没有了。

但是,如果不允许你更改代码,但是你必须对它进行testing,而以这种尴尬的方式,还是有希望的。 使用一些AOP工具(例如AspectJ),你可以将代码编织到超类方法中,并完全避免执行(yuck)。 如果使用代理,这不起作用,您必须使用字节码修改(加载时间编织或编译时间编织)。 PowerMock和PowerMockito也有支持这种技巧的模拟框架。

我build议你去重构,但如果这不是一个选项,你在一些严重的黑客乐趣。

如果你真的没有重构的select,你可以模拟/存根在超级方法调用一切例如

  class BaseService { public void validate(){ fail(" I must not be called"); } public void save(){ //Save method of super will still be called. validate(); } } class ChildService extends BaseService{ public void load(){} public void save(){ super.save(); load(); } } @Test public void testSave() { ChildService spy = Mockito.spy(new ChildService()); // Prevent/stub logic in super.save() Mockito.doNothing().when((BaseService)spy).validate(); // When spy.save(); // Then verify(spy).load(); } 

考虑将来自ChildService.save()方法的代码重构为不同的方法,并testing新的方法而不是testingChildService.save(),这样可以避免对super方法的不必要的调用。

例:

 class BaseService { public void save() {...} } public Childservice extends BaseService { public void save(){ newMethod(); super.save(); } public void newMethod(){ //some codes } } 

在调用超类方法的子类中创build一个受保护的包(假定testing类在同一个包中),然后在重写的子类方法中调用该方法。 然后你可以通过使用间谍模式在你的testing中设置这个方法的期望值。 不是很漂亮,但肯定比在testing中处理超级方法的所有期望设置要好

原因是你的基类没有被公开,那么Mockito由于可见性而不能拦截它,如果你把基类改为public,或者@Override在子类中(作为public),那么Mockito可以正确地嘲笑它。

 public class BaseService{ public boolean foo(){ return true; } } public ChildService extends BaseService{ } @Test @Mock ChildService childService; public void testSave() { Mockito.when(childService.foo()).thenReturn(false); // When assertFalse(childService.foo()); } 

也许最简单的select,如果inheritance是有意义的是创build一个新的方法(包私人??)调用超级(让我们称之为superFindall),窥探真正的实例,然后嘲笑的方式,你想模拟的superFindAll()方法父类一。 在覆盖面和可见度方面,这不是一个完美的解决scheme,但它应该能够完成这项工作,而且很容易实施。

  public Childservice extends BaseService { public void save(){ //some code superSave(); } void superSave(){ super.save(); } }