SpringBoot中单元测试如何对包含AopContext.currentProxy()的方法进行测试

springboot,单元测试,如何,包含,aopcontext,currentproxy,方法,进行,测试 · 浏览次数 : 179

小编点评

**问题分析:** 在AopContext中调用自身的函数时,出现 `java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context` 错误。 **解决方案:** 1. **使用`@Mock`注解模拟`AopContext`中的静态方法:** - 创建一个`MockStatic`对象,其中包含 `currentProxy()` 方法的返回值。 - 在`@BeforeEach`方法中设置`aopContextMockedStatic`。 2. **使用`@Mock`注解模拟`OrderServiceImpl`的`insertDemo()`方法:** - 创建一个`Mock`对象,其中包含`insertDemo()`方法的行为。 - 在`@Mock`中注入`orderServiceMock`。 3. **使用`@Autowired`注解注入`OrderServiceImpl`:** - 在`@BeforeEach`方法中打开Mocks,将`orderServiceMock`注入到`aopContextMockedStatic`中。 4. **在测试方法中访问`AopContext`:** - 在测试方法中使用`aopContextMockedStatic`访问`AopContext`中的静态方法。 **示例代码:** ```java // Mock AopContext @MockStatic private MockedStatic aopContextMockedStatic; // Mock OrderServiceImpl @Mock private OrderServiceImpl orderServiceMock; // Inject OrderServiceImpl into AopContext @Autowired private AopContext aopContext; // Set 'exposeProxy' property to 'true' aopContextMockedStatic.when(AopContext::currentProxy).thenReturn(orderServiceMock); // Perform test int result = orderServiceUnderTest.insertOrder(); // Assert result assertThat(result).isEqualTo(1); ```

正文

今天在工作中遇到一个问题,一个Service类中有一个方法,其中使用了 AopContext.currentProxy() 去访问自身的函数,例如

int result = ((OrderServiceImpl) AopContext.currentProxy()).save();

单元测试方法如下:

@InjectMocks
private OrderServiceImpl orderServiceUnderTest;

@Test
@DisplayName("AopContext测试")
public void test() {
    int result = orderServiceUnderTest.insertDemo();
    assertThat(result).isEqualTo(1);
}

但是在运行测试的时候出现了 java.lang.IllegalStateException: Cannot find current proxy: Set 'exposeProxy' property on Advised to 'true' to make it available, and ensure that AopContext.currentProxy() is invoked in the same thread as the AOP invocation context.

这时候需要将AopContext的静态方法也mock,同时,需要将被测类 OrderServiceImpl 再注入一次,注入到AopContext中。

具体代码如下:

public class SpringTestDemoApplicationTests {
    @InjectMocks
    private OrderServiceImpl orderServiceUnderTest;

    @Spy
    private orderServiceImpl orderServiceMock;

    @Mock
    private MockedStatic<AopContext> aopContextMockedStatic;

    @BeforeEach
    public void setup() {
        openMocks(this);
        aopContextMockedStatic.when(AopContext::currentProxy).thenReturn(orderServiceMock);
    }

    @Test
    @DisplayName("AopContext测试")
    public void test() {
        int result = orderServiceUnderTest.insertOrder();
        assertThat(result).isEqualTo(1);
    }

    @AfterEach
    public void tearDown() {
        aopContextMockedStatic.close();
    }
}

如果proxy对象调用的方法是通过@Autowired注解注入的对象,可能会出现NPE。此时需要将proxy对象的注解由@Spy 改成 @Mock,并通过mockito模拟该方法的行为。而这个方法本身需要另外写一个测试方法。

与SpringBoot中单元测试如何对包含AopContext.currentProxy()的方法进行测试相似的内容:

SpringBoot中单元测试如何对包含AopContext.currentProxy()的方法进行测试

今天在工作中遇到一个问题,一个Service类中有一个方法,其中使用了 AopContext.currentProxy() 去访问自身的函数,例如 int result = ((OrderServiceImpl) AopContext.currentProxy()).save(); 单元测试方法如下

Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了

如何阻止 Java SpringBoot Test 单元测试中包括多线程时,没跑完就结束了 使用 CountDownLatch CountDownLatch、CyclicBarrier 使用区别 多线程 ThreadPoolTaskExecutor 应用 Java BasePooledObjectF

SpringBoot中几种好用的代码生成器(基于Mybatis-plus生成entity、mapper、xml等)

前言 熟悉Spring框架的同学一定都知道MVC开发模式吧,控制器(Controller)、业务类(Service)、持久层(Repository)、数据库映射(Mapper)、各种DO类构成了我们服务端的代码。初学的时候,觉得新鲜手写这些东西不觉得有啥,但是写久了就会觉得很烦。好不容易在数据库中写

[转帖]springboot中使用skywalking实现日志追踪

文章目录 SkyWalking分布式追踪系统介绍主要架构 环境引入依赖配置Log4j2下载编译好的8.7.0版本包使用探针实现日志追踪启动脚本启动Java服务访问服务 使用UI切换存储方式 SkyWalking分布式追踪系统 介绍 Skywalking是一个国产的开源框架,2015年有吴晟个人开源,

Java SpringBoot 中,动态执行 bean 对象中的方法

根据不同的条件,调用不同的 bean 对象,执行对象中的方法

SpringBoot 集成 Quartz + MySQL

Quartz 简单使用 Java SpringBoot 中,动态执行 bean 对象中的方法 源代码地址 => https://gitee.com/VipSoft/VipBoot/tree/develop/vipsoft-quartz 工作原理解读 只要配置好 DataSource Quartz 会

[转帖]SpringBoot之RedisTemplate操作redis出现\xAC\xED\x00\x05t\x00\x08乱码问题

http://qclog.cn/1118 在SpringBoot中使用RedisTemplate操作redis时,会出现\xAC\xED\x00\x05t\x00\x08这种乱码问题,特别是在使用中文时。原因是因为RedisTemplate中key和value的序列化方式都默认使用了jdk的序列化方

java与es8实战之五:SpringBoot应用中操作es8(带安全检查:https、账号密码、API Key)

SpringBoot应用中操作es8,本篇重点是如何连接带安全检查的es8服务端(https、账号密码、API Key)

java与es8实战之四:SpringBoot应用中操作es8(无安全检查)

最简单的,在SpringBoot应用中使用ES官方库操作ES8

[转帖]SpringBoot配置SSL 坑点总结【密码验证失败、连接不安全】

文章目录 前言1.证书绑定问题2.证书和密码不匹配3.yaml配置文件问题3.1 解密类型和证书类型是相关的3.2 配置文件参数混淆 后记 前言 在SpringBoot服务中配置ssl,无非就是下载证书设置一下配置文件的问题,这里主要记录我在配置的过程中遇到的坑点。 如果是新手上道的话建议结合其他的