使用Jest假计时器测试Cache TTL过期场景遇问题
解决@isaacs/ttlcache与Jest假计时器不兼容的问题
问题根源
@isaacs/ttlcache默认依赖系统原生时间戳判断缓存过期,不会自动适配Jest的假计时器。调用jest.advanceTimersByTime()仅会推进Jest模拟的时间线,缓存内部的过期逻辑仍基于真实系统时间,因此无法触发过期行为。
解决方案
1. 让TTLCache使用Jest假时间
实例化TTLCache时,通过now选项注入自定义时间获取函数,绑定到Jest控制的Date.now():
import TTLCache from '@isaacs/ttlcache'; const DATA_KEY = 'barks'; // 关键配置:让缓存使用Jest假时间 const dataCache = new TTLCache({ ttl: 60_000, checkAgeOnGet: true, max: 1, now: () => Date.now() }); export const getCachedData = async (): Promise<string> => { if (!dataCache.has(DATA_KEY)) { dataCache.set(DATA_KEY, 'new-item'); } console.log('remainingTTL', dataCache.getRemainingTTL(DATA_KEY)); return dataCache.get(DATA_KEY); };
2. 调整测试逻辑(修正行为误区)
原测试用例存在逻辑偏差:getCachedData会在缓存不存在时自动重建缓存。即使缓存过期,第二次调用该函数会因has(DATA_KEY)返回false,重新写入新缓存,最终返回new-item而非undefined。
测试缓存过期后直接获取的结果
jest.useFakeTimers(); describe('ttlCaching', () => { // 每次测试前重置缓存和计时器,避免状态污染 beforeEach(() => { dataCache.clear(); jest.clearAllTimers(); }); test('Cache returns undefined after TTL expires', async () => { // 首次调用设置缓存 await getCachedData(); // 推进时间超过TTL阈值 jest.advanceTimersByTime(100_000); // 直接调用缓存get方法,不触发自动重建 expect(dataCache.get(DATA_KEY)).toBeUndefined(); }); // 可选:测试缓存过期后自动重建的行为 test('Re-creates cache when TTL has expired', async () => { expect(await getCachedData()).toEqual('new-item'); jest.advanceTimersByTime(100_000); // 缓存过期后,函数自动重建缓存 expect(await getCachedData()).toEqual('new-item'); // 验证新缓存的剩余TTL expect(dataCache.getRemainingTTL(DATA_KEY)).toBeGreaterThan(50_000); }); });
3. 额外注意事项
- 每个测试前必须调用
dataCache.clear()和jest.clearAllTimers(),避免测试用例间状态污染 - Jest 27+版本可使用
jest.useFakeTimers({ doNotFake: ['nextTick'] }),避免干扰其他异步逻辑
内容的提问来源于stack exchange,提问作者Lemour
相关产品推荐
相关产品推荐

