如何为使用Partials实现的服务编写单元测试并mock依赖model
单元测试实现方案
一、可测试性评估与代码调整建议
你现有的代码已经通过偏函数提前绑定model依赖,本身已经符合依赖注入的设计思路,可测试性基础很好,只需要做无破坏性的小调整即可大幅降低测试成本:
- 原有代码只导出了绑定了真实model的
getSomeService实例生成函数,建议同时导出内部的init和SomeService,测试时可以直接传入mock model,无需依赖框架的模块mock能力,调整后的导出代码如下:
// 原有业务逻辑完全不变,仅修改导出部分,不影响现有业务代码的使用 module.exports = { getSomeService, // 保留原有对外暴露的API,业务侧导入使用逻辑无任何变化 init, // 测试场景专用,可传入自定义model生成服务实例 SomeService // 额外导出更灵活,可直接构造服务实例 };
如果不想修改原有导出逻辑也可以不调整,直接用框架的模块mock能力即可。
二、Mock Model的实现方式
方案1:调整导出后直接传入mock(更推荐,逻辑清晰无额外依赖)
以常用的Jest测试框架为例,测试代码如下:
// 导入导出的init方法 const { init } = require('./你的服务文件路径'); // 构造mock model,模拟所有需要调用的方法 const mockModel = { getSomething: jest.fn(), createSomething: jest.fn(), deleteSomething: jest.fn() }; // 用mock model生成测试用的服务实例 const getTestService = init(mockModel); const testService = getTestService(); // 测试成功场景 test('getSomething 传入正确ID返回对应数据', () => { // 预设mock方法返回值 const mockRes = { id: 123, content: '测试数据' }; mockModel.getSomething.mockReturnValue([mockRes, null]); const result = testService.getSomething(123); // 验证调用参数和返回结果 expect(mockModel.getSomething).toHaveBeenCalledWith(123); expect(result).toEqual(mockRes); }); // 测试异常场景 test('getSomething 查询出错时返回错误对象', () => { const mockErr = new Error('ID不存在'); mockModel.getSomething.mockReturnValue([null, mockErr]); const result = testService.getSomething(999); expect(result).toEqual(mockErr); });
createSomething、deleteSomething的测试逻辑和上述写法完全一致,只需要修改对应的mock方法返回值即可。
方案2:不调整原有导出,直接mock依赖模块
如果不想修改业务代码的导出规则,可以直接mock依赖的../models模块,示例如下:
// 先mock整个models模块 jest.mock('../models', () => ({ getSomething: jest.fn(), createSomething: jest.fn(), deleteSomething: jest.fn() })); const mockModel = require('../models'); // 导入原有导出的服务生成函数 const getSomeService = require('./你的服务文件路径'); const testService = getSomeService(); // 后续测试用例写法和方案1完全一致
这种方式无需修改业务代码,但是依赖测试框架的模块mock能力,跨框架迁移成本比方案1高。
三、可选优化建议
- 可以给
SomeService的model入参增加简单的校验逻辑,避免传入缺少方法的非法model时出现未捕获的运行时报错 - 目前你已经统一了所有model方法返回[数据, 错误]的元组格式,保持该规范即可,无需额外调整。
内容的提问来源于stack exchange,提问作者thewebjackal
相关产品推荐
相关产品推荐

