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

如何为CacheManager的全量缓存清除方法编写单元测试

问题背景

我有一个用于驱逐所有缓存的方法,对应实现代码如下:

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cache.CacheManager;
import org.springframework.stereotype.Service;

import com.admin.AdminResponse;

@Service
public class CachingService {
    
    private final static Logger logger = LoggerFactory.getLogger(CachingService.class);

    @Autowired
    protected CacheManager cacheManager;
    
    public AdminResponse evictAllCaches() {
        logger.info("Start - Clearing of cache");
        cacheManager.getCacheNames().parallelStream()
          .forEach(cacheName -> cacheManager.getCache(cacheName).clear());
            
        AdminResponse adminResponse = new AdminResponse();
        adminResponse.setMessage("ok");
        logger.info("End - Clearing of cache");
        return adminResponse;
    }
}

以下是我当前尝试编写的单元测试代码:

import static org.junit.jupiter.api.Assertions.assertEquals;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collection;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.cache.concurrent.ConcurrentMapCacheFactoryBean;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import com.admin.AdminResponse;

@ExtendWith(SpringExtension.class)
public class CachingServiceTest {
    
    @InjectMocks
    private CachingService testCachingService;

    @Mock
    protected CacheManager cacheManager;
    
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void testEvictAllCaches() {
        AdminResponse adminResponse = testCachingService.evictAllCaches();
        assertEquals("ok", adminResponse.getMessage());
    }
    
}

我目前不了解如何为如下核心缓存清除逻辑编写覆盖校验的单元测试:

cacheManager.getCacheNames().parallelStream()
          .forEach(cacheName -> cacheManager.getCache(cacheName).clear());

恳请提供相关实现指导。

实现方案

你需要通过Mockito模拟缓存管理器的行为,校验所有缓存的clear()方法都被正确调用,完整改造后的测试代码如下:

import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.mockito.Mockito.times;
import static org.mockito.Mockito.verify;
import static org.mockito.Mockito.when;

import java.util.Arrays;
import java.util.List;

import org.junit.Before;
import org.junit.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.InjectMocks;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.springframework.cache.Cache;
import org.springframework.cache.CacheManager;
import org.springframework.test.context.junit.jupiter.SpringExtension;

import com.admin.AdminResponse;

@ExtendWith(SpringExtension.class)
public class CachingServiceTest {
    
    @InjectMocks
    private CachingService testCachingService;

    @Mock
    protected CacheManager cacheManager;

    // 模拟两个测试用缓存
    @Mock
    private Cache mockCache1;
    @Mock
    private Cache mockCache2;
    
    @Before
    public void setup() {
        MockitoAnnotations.initMocks(this);
    }
    
    @Test
    public void testEvictAllCaches() {
        // 1. 构造模拟数据:给缓存管理器返回两个测试缓存名
        List<String> testCacheNames = Arrays.asList("cache1", "cache2");
        when(cacheManager.getCacheNames()).thenReturn(testCacheNames);
        
        // 2. 模拟根据缓存名获取缓存对象的行为
        when(cacheManager.getCache("cache1")).thenReturn(mockCache1);
        when(cacheManager.getCache("cache2")).thenReturn(mockCache2);

        // 3. 执行待测试方法
        AdminResponse adminResponse = testCachingService.evictAllCaches();
        
        // 4. 校验返回结果
        assertEquals("ok", adminResponse.getMessage());

        // 5. 核心校验:确认每个缓存的clear方法都被调用了1次
        verify(mockCache1, times(1)).clear();
        verify(mockCache2, times(1)).clear();
        verify(cacheManager, times(1)).getCacheNames();
    }
    
}

关键逻辑说明

  • 首先模拟CacheManager的getCacheNames()方法,返回你预设的测试缓存名列表,覆盖遍历逻辑
  • 给每个预设的缓存名绑定对应的Mock缓存对象,避免调用getCache()时返回null
  • 执行完目标方法后,通过verify()校验每个Mock缓存的clear()方法是否被准确调用,同时校验缓存管理器的相关方法调用次数符合预期,就能100%覆盖核心缓存清除逻辑
  • 你原来的测试代码里导入了没用的类(比如ArrayList、ConcurrentMapCacheFactoryBean),可以直接删掉,避免无用依赖

额外提示:如果你的项目用的是JUnit5,@Before注解可以替换为@BeforeEach,MockitoAnnotations.initMocks(this)也可以替换为Mockito.openMocks(this)并手动管理关闭,适配最新版Mockito的API要求。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.27 17:25:02