如何用Sinon模拟fs模块的statSync函数?多次尝试未生效
解决Sinon无法Stub fs.statSync的问题
问题概述
编写了一个判断文件夹创建时间是否超过24小时阈值的函数,测试时尝试用Sinon Stub fs模块的statSync方法,但始终无法生效:控制台打印真实的stat结果,Stub的callCount为0,尝试了returns、callsFake、resolves等多种Stub方式均无效。
核心原因
原函数中**statSync的导入方式**导致Stub失效:如果原函数是直接导入单个方法import { statSync } from 'fs',而测试代码中Stub的是fs.statSync,这两个并非同一个引用。ES模块的单个导入会直接绑定原始方法,Sinon对fs对象上的statSync进行Stub不会影响原函数中已导入的独立statSync方法。
解决方案
方案1:修改原函数的导入方式
将原函数改为导入整个fs模块,调用fs.statSync,这样测试中对fs.statSync的Stub就能覆盖到实际调用:
import * as fs from 'fs'; export const isFolderOlderThanThreshold = (path: string) => { console.log('isFolderOlderThanThreshold'); const rootFolderStat = fs.statSync(path); // 使用fs.statSync而非单独导入的statSync console.log('rootFolderStat = ', rootFolderStat); const dateToCompare = new Date(); dateToCompare.setTime(dateToCompare.getTime() - (24 * 60 * 60 * 1000)); console.log('Creation time of folder %s is %s and threshold time is %s', path, rootFolderStat.birthtime, dateToCompare); return rootFolderStat.birthtimeMs <= dateToCompare.getTime(); };
方案2:使用proxyquire替换单个导入的方法
如果不想修改原函数的导入逻辑,可以用proxyquire工具在测试时替换原函数中导入的statSync:
- 先安装依赖:
npm install proxyquire --save-dev
- 修改测试用例:
import proxyquire from 'proxyquire'; import sinon from 'sinon'; import * as fs from 'fs'; it('should check created time in upload folder', () => { storageRepository.stubs.getRootStorageLocation.returns(rootStorageLocation); const date = new Date('2023-02-21T08:16:25.580Z'); const obj = { birthtimeMs: BigInt(date.getTime()), birthtime: date } as fs.BigIntStats; const statSyncStub = sinon.stub().returns(obj); // 用proxyquire加载目标模块,替换其中的statSync const { isFolderOlderThanThreshold } = proxyquire('../path/to/your/module', { 'fs': { statSync: statSyncStub } }); const result = isFolderOlderThanThreshold(join(rootStorageLocation, 'aaa')); // 断言结果:2023年的时间早于当前时间减24小时,返回true expect(result).to.be.true; // 断言Stub被调用过一次 expect(statSyncStub.calledOnce).to.be.true; console.log('statSyncStub.callCount = ', statSyncStub.callCount); });
测试用例关键修正点
- 同步方法不能用resolves:
statSync是同步方法,Stub时要用returns或callsFake,不能用resolves(resolves是给异步Promise函数用的)。 - 避免不必要的IO操作:测试时无需实际创建/删除文件夹,因为已经Stub了
statSync,直接模拟返回值即可。
内容的提问来源于stack exchange,提问作者Shubham
相关产品推荐
相关产品推荐

