mockito 在SpyBean中执行JpaRepository中的方法

lmyy7pcs  于 2022-11-08  发布在  其他
关注(0)|答案(1)|浏览(199)

我正在用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,但没有找到正确的解决方案。
有什么想法吗?

pw136qt2

pw136qt21#

这是一个非常奇怪的案例。让我们先了解这种行为的原因,然后再设法找出解决办法。
当我们深入研究Mockito代码时,我们会发现在本例中,异常是在这里抛出的(CallsRealMethods类):

public void validateFor(InvocationOnMock invocation) {
    if (new InvocationInfo(invocation).isAbstract()) {
        throw cannotCallAbstractRealMethod();
    }
}

基于以下代码(InvocationInfo类)验证方法是否为抽象:

public boolean isAbstract() {
    return (method.getModifiers() & Modifier.ABSTRACT) != 0;
}

其简单地验证该方法是否具有抽象标志(位)集,并且在X1 M2 N1 X接口(其中X1 M3 N1 X和X1 M4 N1 X是源)的情况下,其显然为真。
由于来自Spring管理的仓库的方法调用是代理的(在本例中--到SimpleJpaRepository示例,read more here),Mockito无法知道这里调用的真正方法不会导致问题--它是抽象的,但是它被Spring拦截了。所以基本上-- Mockito在本例中抛出这样一个异常是正确的,没有任何额外的上下文。
我们能做些什么呢?在你知道问题的原因之后,可能有各种各样的解决方法--我将向你展示我想到的第一个方法,但我想可能还有其他我只是用一个伪类覆盖了接口中的抽象方法,这个伪类将测试过的方法调用委托给真正的存储库。使用Mockito可以很容易地发现这样的伪类示例--多亏了它,您提供的代码工作得很好(我没有注意到您正在存根deleteAll方法,所以在我的例子中是findById)。请参见下面的代码以及内联注解。
第一个
我已经在GitHub存储库中复制了它,你可以在那里找到所有的代码。上面显示的测试(以及存储库中的测试)通过了。

相关问题