【问题标题】:Mocking a class with @Transactional method with Mockito使用 Mockito 使用 @Transactional 方法模拟一个类
【发布时间】:2019-02-13 21:39:12
【问题描述】:

我有一个服务,一个 bean,它包含一个 @Transactional 方法:

public class InMessageService {

...

    @Transactional

    public boolean retryInMessage(String messageId) {

    ...

    }

}

为了测试,我尝试使用 Mockito 模拟该服务:

@Bean
@Primary
public InMessageService inMessageService() {
    return Mockito.mock(InMessageService.class);
}

当我开始测试时,结果是以下异常:

   Caused by: org.springframework.aop.framework.AopConfigException: Could not generate CGLIB
subclass of class somePackage.InMessageService$MockitoMock$156222813: Common
causes of this problem include using a final class or a non-visible class;nested exception is
org.springframework.cglib.core.CodeGenerationException: java.lang.NoClassDefFoundError-->
somePath/InMessageService$MockitoMock$156222813

我想提一下,相同的代码适用于 spring-boot 1.2.1 和 Mockito 1.10.19。我尝试使用 spring boot 2.1.1 和 Mockito 2.23.0 运行上述代码

到目前为止我的观察:

  • 无论我使用 2.1.0 和 2.23.0 之间的哪个 Mockito 版本,异常都是一样的。我不能(也不想)使用旧版本的 Mockito,因为该项目不再编译
  • 如果我临时删除@Transactional 注释,则不会引发异常。

有什么想法可以通过升级 Spring Boot 进行调整以使测试再次工作?

谢谢!

【问题讨论】:

    标签: spring-boot junit mockito cglib


    【解决方案1】:

    从 2.1.0 版开始,Mockito 保留了代理方法的注释。这意味着 Spring 尝试代理声明事务注释的模拟类,但失败了,因为模拟方法是最终的。

    以前,Mockito 剥离了这些注释,因为缺少事务会导致任何真正的方法调用失败。

    为避免这种情况,您需要去除模拟的注释。您可以使用MockSettings.withoutAnnotations 来执行此操作。

    【讨论】:

    • 我明白了。注释不是由覆盖方法“继承”的吗?我尝试了您的解决方法建议,并且子类也遇到了相同的异常。
    • 如果您不想使用内联模拟制作器,我们已经添加了一项功能来去除注释。请参阅我的更新答案。
    • 我刚试过 Mockito.mock(InMessageService.class, Mockito.withSettings().withoutAnnotations());它仍然无法正常工作。还有比这更多的事吗?
    猜你喜欢
    • 2015-10-14
    • 1970-01-01
    • 2018-02-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2023-03-20
    • 1970-01-01
    • 2015-12-13
    相关资源
    最近更新 更多