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
相关产品推荐
相关产品推荐

