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

如何在Jest中按测试用例修改lru-cache构造函数返回对象实现

解决Jest中lru-cache的get方法Mock实现不生效问题

问题场景

项目中使用lru-cache的方式如下:

const LRU = require('lru-cache');
const cache = new LRU({
  max: 500,
  ttl: 1000 * 60 * 15,
  updateAgeOnGet: false,
  updateAgeOnHas: false,
});

// 被测试函数依赖该cache实例
function myFunction(key) {
  return cache.get(key);
}

尝试用Jest模拟lru-cache时,在测试用例中修改get方法的mock实现始终不生效,示例代码:

const LRU = require('lru-cache');
jest.mock('lru-cache');

it('should return custom response', () => {
  LRU.mockImplementation(() => ({
    get: jest.fn().mockImplementation(data => ({ response: data })),
    set: jest.fn()
  }));

  // 调用被测试函数时,get方法仍为默认mock,自定义实现未生效
  const result = myFunction('test-key');
});

但直接在测试文件内修改已实例化的cache.get却能生效:

cache.get.mockImplementation(identifier => ({ response: identifier }));

问题原因

被测试模块在导入阶段就已经执行new LRU()创建了缓存实例,而Jest的模块mock是在模块加载时替换的。如果在测试用例中才修改LRU.mockImplementation,此时被测试模块已经持有了之前的mock实例,新的mock实现无法作用到已创建的实例上。

解决方案

方案1:重置模块并在测试用例中重新导入被测试模块

使用jest.resetModules()在每个测试前重置模块缓存,先修改mock实现,再导入被测试模块,确保模块使用最新的mock构造函数:

jest.mock('lru-cache');
const LRU = require('lru-cache');

describe('myFunction', () => {
  beforeEach(() => {
    jest.resetModules();
    jest.clearAllMocks();
  });

  it('should return custom response', () => {
    // 先设置LRU的mock实现
    LRU.mockImplementation(() => ({
      get: jest.fn().mockImplementation(data => ({ response: data })),
      set: jest.fn()
    }));

    // 再导入被测试模块
    const { myFunction } = require('./path-to-your-module');

    const result = myFunction('test-key');
    expect(result).toEqual({ response: 'test-key' });
    expect(LRU).toHaveBeenCalledTimes(1);
  });

  it('should return fixed value in another test', () => {
    LRU.mockImplementation(() => ({
      get: jest.fn().mockReturnValue('fixed-value'),
      set: jest.fn()
    }));

    const { myFunction } = require('./path-to-your-module');
    const result = myFunction('any-key');
    expect(result).toBe('fixed-value');
  });
});

方案2:让mock返回可复用的mock函数

提前定义get和set为可修改的jest mock函数,无需重新mock构造函数,直接在测试用例中修改get的实现:

const LRU = require('lru-cache');
// 定义可复用的mock函数
const mockGet = jest.fn();
const mockSet = jest.fn();

jest.mock('lru-cache', () => {
  return jest.fn(() => ({
    get: mockGet,
    set: mockSet
  }));
});

// 导入被测试模块
const { myFunction } = require('./path-to-your-module');

describe('myFunction', () => {
  beforeEach(() => {
    jest.clearAllMocks();
  });

  it('should return custom response', () => {
    mockGet.mockImplementation(data => ({ response: data }));
    const result = myFunction('test-key');
    expect(result).toEqual({ response: 'test-key' });
    expect(mockGet).toHaveBeenCalledWith('test-key');
  });

  it('should return null when key not found', () => {
    mockGet.mockReturnValue(null);
    const result = myFunction('non-existent-key');
    expect(result).toBeNull();
  });
});

方案3:使用jest.spyOn模拟get方法

若无需mock整个lru-cache模块,仅需模拟get方法,可直接用jest.spyOn替换实例上的方法:

// 导入被测试模块和cache实例
const { myFunction, cache } = require('./path-to-your-module');

describe('myFunction', () => {
  it('should return custom response', () => {
    const spy = jest.spyOn(cache, 'get').mockImplementation(data => ({ response: data }));
    
    const result = myFunction('test-key');
    expect(result).toEqual({ response: 'test-key' });
    
    // 测试完成后恢复原方法
    spy.mockRestore();
  });
});

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.11 20:15:16