You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Spring Data JPA中@Cacheable缓存无法通过单元测试验证如何解决?

问题根因

你当前编写的是普通单元测试,手动实例化了UserServiceImpl类,没有加载Spring上下文。而@Cacheable注解的缓存功能基于Spring AOP动态代理实现,只有调用Spring容器管理的Bean对象时才会触发缓存切面逻辑,直接调用手动创建的类实例方法时注解完全不生效,因此三次get调用都会触发findById执行,导致验证失败。

正确测试实现

推荐使用Spring Boot测试框架加载必要上下文,用容器管理的代理对象验证缓存逻辑:

import org.springframework.boot.test.context.SpringBootTest
import org.springframework.cache.annotation.EnableCaching
import org.springframework.boot.test.mock.mockito.MockBean
import org.springframework.beans.factory.annotation.Autowired
import io.mockk.every
import io.mockk.verify
import org.junit.jupiter.api.Test

@SpringBootTest
@EnableCaching
class UserServiceImplTest {
    // 替换容器中的真实Repository为Mock对象
    @MockBean
    private lateinit var userRepository: UserRepository

    // 注入容器生成的AOP代理对象,才能触发@Cacheable逻辑
    @Autowired
    private lateinit var userService: UserService

    @Test
    fun `get should use caching`() {
        // given
        val user = UserEntity(1, "Anna", "anna@gmail.com")
        every { userRepository.findById(user.id!!) } returns Optional.of(user)

        // when
        repeat(3) {
            userService.get(user.id!!)
        }

        // then
        verify(exactly = 1) { userRepository.findById(user.id!!) }
    }
}

注意事项

  • 不要手动实例化UserServiceImpl,必须通过@Autowired注入容器管理的代理对象
  • 确保项目已经引入spring-boot-starter-cache依赖,且缓存配置正确(默认用内存缓存即可跑通测试)
  • 如果要避免不同测试用例的缓存互相干扰,可以在测试类上加@DirtiesContext,或者注入CacheManager在测试执行前后清空users缓存
  • 如果不需要启动全量Spring上下文,可以用@ContextConfiguration指定仅加载缓存配置和Service类,减少测试启动耗时

内容的提问来源于stack exchange,提问作者NeverSleeps

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.09.29 17:36:05