为什么使用Jest无法mock JavaScript的fs.readFileSync方法?
问题修复方案
核心错误原因
- 模块初始化时机早于mock赋值:测试代码顶部先引入了
./secret模块,模块加载时会立刻执行getSecret初始化secretConfig,此时fs的mock返回值还未设置,只能拿到undefined - 同步方法误用异步mock接口:
fs.readFileSync是同步方法,第一个测试用例用了仅适配异步Promise方法的mockResolvedValue设置返回值,不生效 - 变量覆盖:第二个测试用例内部定义了
const secret = 'secret',覆盖了顶部导入的secret模块对象,访问字符串的kafka_keystore_password属性自然返回undefined
修复后的测试代码
无需修改业务代码,仅调整测试逻辑即可:
let fs = require('fs') jest.mock('fs'); describe('secret read files', () => { afterEach(jest.resetModules()); // 每次测试重置模块缓存,保证重新导入时会重新初始化 afterEach(jest.restoreAllMocks); it('should read secret from file', () => { // 先设置mock返回值,再导入模块 fs.readFileSync.mockReturnValue("randomPrivateKey"); const secret = require('./secret'); const secretMessage = secret.kafka_keystore_password; expect(fs.readFileSync).toHaveBeenCalledWith('/etc/secrets/kafka_keystore_password.txt', 'utf8'); expect(secretMessage).toEqual('randomPrivateKey'); }) }) describe('getSecretsFromFile', () => { afterEach(jest.resetModules()); afterEach(jest.restoreAllMocks); it('returns secrets if file is present', () => { fs.readFileSync.mockReturnValue('randomPrivateKey'); const secret = require('./secret'); const secretMessage = secret.kafka_keystore_password; expect(secretMessage).toEqual('randomPrivateKey'); }); });
可选优化(业务代码更易测试)
如果允许调整业务代码,建议把静态导出的配置改为函数导出,避免模块加载时就执行IO操作,使用更灵活:
// 待测试文件修改后代码 const fs = require('fs'); const read_file = (path) => { try { const data = fs.readFileSync(path, 'utf8'); return data; } catch (err) { console.error('Error in read_file', err); throw err; } }; const getSecret = secretName => { try { return read_file(`/etc/secrets/${secretName}.txt`); } catch (err){ throw err; } }; // 改为函数导出,调用时才初始化 const getSecretConfig = () => ({ kafka_keystore_password: getSecret('kafka_keystore_password') }); module.exports = getSecretConfig;
修改后测试时不需要考虑模块导入时机,直接调用函数即可:
const getSecretConfig = require('./secret'); let fs = require('fs') jest.mock('fs'); describe('secret read files', () => { afterEach(jest.restoreAllMocks); it('should read secret from file', () => { fs.readFileSync.mockReturnValue("randomPrivateKey"); const secretConfig = getSecretConfig(); expect(secretConfig.kafka_keystore_password).toEqual('randomPrivateKey'); }) })
内容的提问来源于stack exchange,提问作者amarnath harish
相关产品推荐
相关产品推荐

