我正在用JpaRepository
编写一个服务测试。它工作得很好,但是我想从数据库中检查一个有一系列失败的案例。
我创建了一个测试,并注入了一个@SpyBean
作为我的Repository
类型的bean。一般来说,我希望在快乐路径场景中使用一个真正的存储库bean,我只希望在一些情况下当我想模拟一个失败时中断它。
它工作正常,但我想检查对单个方法的调用序列,如下所示:exception -> ok -> exception
-我使用批处理,所以这就是为什么我喜欢用这种方式测试它。
我试图这样嘲弄这种行为:
doThrow(...).doCallRealMethod().doThrow(...)
.when(mySpyBean).deleteAll(any());
以模拟该序列。
不幸的是,它失败了,并出现异常和如下消息:
Cannot call abstract real method on java object!
Calling real methods is only possible when mocking non abstract method.
好的,我收到了这个消息,但是我只想调用如果我没有设置任何方法Mockito方法(比如默认行为)的话会调用的方法。我只想在第二次调用中委托一个对Spring中注册的真实bean的调用。
我也尝试了X1 M4 N1 X,但没有找到正确的解决方案。
有什么想法吗?
1条答案
按热度按时间pw136qt21#
这是一个非常奇怪的案例。让我们先了解这种行为的原因,然后再设法找出解决办法。
当我们深入研究Mockito代码时,我们会发现在本例中,异常是在这里抛出的(
CallsRealMethods
类):基于以下代码(
InvocationInfo
类)验证方法是否为抽象:其简单地验证该方法是否具有抽象标志(位)集,并且在X1 M2 N1 X接口(其中X1 M3 N1 X和X1 M4 N1 X是源)的情况下,其显然为真。
由于来自Spring管理的仓库的方法调用是代理的(在本例中--到
SimpleJpaRepository
示例,read more here),Mockito无法知道这里调用的真正方法不会导致问题--它是抽象的,但是它被Spring拦截了。所以基本上-- Mockito在本例中抛出这样一个异常是正确的,没有任何额外的上下文。我们能做些什么呢?在你知道问题的原因之后,可能有各种各样的解决方法--我将向你展示我想到的第一个方法,但我想可能还有其他我只是用一个伪类覆盖了接口中的抽象方法,这个伪类将测试过的方法调用委托给真正的存储库。使用Mockito可以很容易地发现这样的伪类示例--多亏了它,您提供的代码工作得很好(我没有注意到您正在存根
deleteAll
方法,所以在我的例子中是findById
)。请参见下面的代码以及内联注解。第一个
我已经在GitHub存储库中复制了它,你可以在那里找到所有的代码。上面显示的测试(以及存储库中的测试)通过了。