升级jsonwebtoken至9.0.0后,Sinon Stub decode函数报错TypeError
解决方案:jsonwebtoken 9.0.0中无法Stub decode函数的问题
问题原因
jsonwebtoken 9.x版本重构了导出逻辑,decode函数通过Object.defineProperty定义时设置了configurable: false,这意味着该属性无法被重新定义或删除,而sinon的stub本质是覆盖原有属性,因此直接操作会抛出TypeError: Cannot redefine property: decode错误。verify函数未采用相同的定义方式,所以可以正常Stub。
可行解决方案
方案1:修改属性可配置性后再Stub
在Stub前先修改decode属性的可配置性,让sinon能够覆盖它:
const jwt = require('jsonwebtoken'); const sinon = require('sinon'); beforeEach(() => { // 获取decode属性的描述符 const decodeDesc = Object.getOwnPropertyDescriptor(jwt, 'decode'); // 修改为可配置 decodeDesc.configurable = true; Object.defineProperty(jwt, 'decode', decodeDesc); // 现在可以正常Stub sinon.stub(jwt, 'decode').returns({ userId: 'test-user-id' }); }); afterEach(() => { // 恢复原始属性(可选,避免影响其他测试) sinon.restore(); });
方案2:使用proxyquire替换整个jsonwebtoken模块
通过proxyquire在测试中注入一个模拟的jsonwebtoken模块,完全规避原有模块的属性限制:
const sinon = require('sinon'); const proxyquire = require('proxyquire'); describe('你的测试套件', () => { let targetModule; let jwtMock; beforeEach(() => { // 创建包含可Stub方法的模拟对象 jwtMock = { decode: sinon.stub().returns({ userId: 'test-user-id' }), verify: sinon.stub().returns({ userId: 'test-user-id' }) }; // 加载目标模块并替换jsonwebtoken为模拟对象 targetModule = proxyquire('../路径/到/你的/模块', { 'jsonwebtoken': jwtMock }); }); it('测试用例示例', () => { // 执行测试逻辑 targetModule.someFunctionUsingJwt(); // 断言decode被调用 sinon.assert.calledOnce(jwtMock.decode); }); });
方案3:直接模拟decode的实现逻辑(临时替代)
如果上述方案无法使用,也可以直接在测试代码中手动模拟decode的行为,比如在目标模块中添加一个可替换的依赖入口:
// 你的业务模块中,将jwt依赖改为可注入 let jwt = require('jsonwebtoken'); // 暴露用于测试的替换方法 if (process.env.NODE_ENV === 'test') { module.exports.setJwt = (mockJwt) => { jwt = mockJwt; }; } // 业务逻辑中使用jwt.decode function yourFunction(token) { return jwt.decode(token); }
然后在测试中替换:
const yourModule = require('../path/to/your/module'); const sinon = require('sinon'); beforeEach(() => { const mockJwt = { decode: sinon.stub().returns({ userId: 'test-id' }), verify: sinon.stub() }; yourModule.setJwt(mockJwt); });
内容的提问来源于stack exchange,提问作者Rasmus Puls
相关产品推荐
相关产品推荐

