如何使用Jest测试Node.js中依赖外部变量的类静态方法
解决Jest测试中给模块级变量secret赋值的问题
针对你代码里模块级的secret变量,有几种方法可以在Jest测试中修改它,从而覆盖getSecrt方法的两种分支:
方法1:添加测试专用的静态setter方法
在原类中添加一个静态方法用来设置secret,不需要暴露变量本身,更安全:
修改vault.js:
let secret; class vaultclass { static getSecrt(key) { if (secret) { return secret[key]; } else return null; } // 仅用于测试的setter方法 static setSecret(newSecret) { secret = newSecret; } } module.exports = vaultclass;
对应的Jest测试代码(vault.test.js):
const vaultclass = require('./vault'); describe('vaultclass.getSecrt', () => { // 每次测试前重置secret,避免测试用例互相污染 beforeEach(() => { vaultclass.setSecret(null); }); test('当secret未设置时返回null', () => { expect(vaultclass.getSecrt('anyKey')).toBeNull(); }); test('当secret存在时返回对应key的值', () => { vaultclass.setSecret({ testKey: 'testValue' }); expect(vaultclass.getSecrt('testKey')).toBe('testValue'); }); });
方法2:导出secret变量(简单直接)
如果不介意暴露secret,可以直接把它和类一起导出,测试时直接修改:
修改vault.js:
let secret; class vaultclass { static getSecrt(key) { if (secret) { return secret[key]; } else return null; } } // 导出secret供测试使用 module.exports = { vaultclass, secret };
测试代码:
const { vaultclass } = require('./vault'); describe('vaultclass.getSecrt', () => { beforeEach(() => { // 重置原模块的secret变量 const vaultModule = require('./vault'); vaultModule.secret = null; }); test('返回null当secret未设置', () => { expect(vaultclass.getSecrt('test')).toBeNull(); }); test('返回secret中对应的值', () => { const vaultModule = require('./vault'); vaultModule.secret = { foo: 'bar' }; expect(vaultclass.getSecrt('foo')).toBe('bar'); }); });
注意:测试里不能直接写secret = { ... },这会在测试模块里重新定义局部变量,无法影响原模块的secret,必须通过模块引用重新赋值。
方法3:使用rewire库(无需修改原代码)
如果不想改动生产代码,可以用rewire库来访问和修改模块内部的私有变量:
- 先安装rewire:
npm install --save-dev rewire
- 测试代码:
const rewire = require('rewire'); const vaultModule = rewire('./vault'); // 获取类的引用 const vaultclass = vaultModule.__get__('vaultclass'); describe('vaultclass.getSecrt', () => { beforeEach(() => { // 重置secret vaultModule.__set__('secret', null); }); test('secret未设置时返回null', () => { expect(vaultclass.getSecrt('test')).toBeNull(); }); test('secret存在时返回对应值', () => { // 设置模块内部的secret变量 vaultModule.__set__('secret', { baz: 'qux' }); expect(vaultclass.getSecrt('baz')).toBe('qux'); }); });
这种方法不需要修改原代码,适合对生产代码改动有严格限制的场景。
内容的提问来源于stack exchange,提问作者Ankit Singh
相关产品推荐
相关产品推荐

