如何用Sinon和TypeScript测试employeeService?Mock后仍执行数据库操作
解决employeeService单元测试中数据库操作未被Mock的问题
问题根源
employeeInfo.ts在模块加载阶段就实例化并调用了getResult(),导致测试启动前就触发了数据库请求- 测试时未正确Mock已导出的单例实例方法,而是错误地尝试Mock类,导致真实数据库操作仍在执行
第一步:修正employeeInfo.ts的代码问题
先修复原代码的语法错误,并移除模块加载时自动执行的数据库调用:
// ../utils/employeeInfo.ts class employeeInfo { private memoizedResult: any = null; public async getResult() { // 修正原代码的变量引用错误 if (!this.memoizedResult) { this.memoizedResult = await this.getData(); } return this.memoizedResult; } async getData() { // get data from database console.log('getting data from database'); return data; } } const EmployeeInfo = new employeeInfo(); // 移除这行自动执行的代码,避免模块加载时触发数据库请求 // EmployeeInfo.getResult(); export default EmployeeInfo;
第二步:编写正确的单元测试(Sinon + TypeScript)
以Mocha测试框架为例,直接Mock已导出的单例实例的getData方法:
// employeeService.test.ts import { expect } from 'chai'; import sinon from 'sinon'; import EmployeeInfo from '../utils/employeeInfo'; import EmployeeService from './employeeService'; describe('employeeService', () => { let getDataStub: sinon.SinonStub; beforeEach(() => { // 直接Stub单例实例的getData方法,返回模拟数据 getDataStub = sinon.stub(EmployeeInfo, 'getData').resolves({ salary: 5000 }); }); afterEach(() => { // 恢复原方法,避免测试用例间互相干扰 getDataStub.restore(); }); it('getSalary应正确调用Mock的getData方法', async () => { const service = new EmployeeService(); const logStub = sinon.stub(console, 'log'); await service.getSalary(); // 验证getData被调用一次 expect(getDataStub.calledOnce).to.be.true; // 验证控制台输出了Mock的数据 expect(logStub.calledWith({ salary: 5000 })).to.be.true; logStub.restore(); }); });
关键注意事项
- 必须直接Stub已导出的单例实例方法,而非
employeeInfo类,因为employeeService依赖的是已实例化的对象 - 所有Stub的方法必须在测试后恢复,防止污染其他测试用例
- 若使用Jest框架,核心逻辑一致,仅需将Sinon的Stub语法替换为
jest.spyOn(EmployeeInfo, 'getData').mockResolvedValue(...)
内容的提问来源于stack exchange,提问作者cam
相关产品推荐
相关产品推荐

