Jest+Supertest测试CreateVendor:跨文件Mock函数失败及404错误
问题解决方案
你当前面临两个核心问题:测试返回404错误、无法正确Mock generateSalt/hashPassword函数,以下是针对性的解决步骤:
一、解决404 Not Found错误
404的核心原因是请求路径不匹配或测试用app实例未正确挂载路由:
- 先确认实际业务中
CreateVendor控制器的路由是否确实是POST /admin/vendor,检查路由注册代码是否给控制器加了/admin前缀 - 验证测试中导入的
app实例是否完成了所有路由初始化,比如是否在测试前执行了路由挂载逻辑 - 临时在测试中添加
await supertest(app).get('/')验证基础响应,排查app实例是否正常工作
另外注意:你测试中Mock了Vendor.find,但控制器实际调用的是findVendor('', email),这个自定义函数如果未被Mock,可能导致逻辑异常,但404优先排查路由问题。
二、正确Mock generateSalt和hashPassword
"Property generateSalt does not exist in the provided object"报错,是因为jest.spyOn仅能Mock对象上的方法,而generateSalt是独立导出的函数,必须用jest.mockMock整个模块:
假设你的工具函数模块utilities.ts导出方式如下:
export const generateSalt = async () => { /* 原逻辑 */ }; export const hashPassword = async (pwd: string, salt: string) => { /* 原逻辑 */ };
修正后的Mock写法
// 在测试文件顶部或describe块内,Mock整个工具模块 jest.mock('../../utilities', () => ({ generateSalt: jest.fn().mockResolvedValue('mocked-salt-123'), hashPassword: jest.fn().mockResolvedValue('mocked-hashed-password') })); // 导入需要验证的mock函数 import { generateSalt, hashPassword } from '../../utilities';
三、完整修正后的测试用例
import request from 'supertest'; import { app } from '../../app'; import { Vendor } from '../../models/Vendor'; import { findVendor } from '../../services/vendorService'; // 假设findVendor在此模块 import { generateSalt, hashPassword } from '../../utilities'; jest.mock('../../utilities', () => ({ generateSalt: jest.fn().mockResolvedValue('test-salt'), hashPassword: jest.fn().mockResolvedValue('test-hashed-pwd') })); describe('CreateVendor function', () => { it('creates a new vendor successfully', async () => { const mockVendorData = { name: 'Test Vendor', email: 'test@vendor.com', password: 'test123', address: 'Test Address', foodType: ['Fast Food'], ownerName: 'Test Owner', phone: '1234567890', pincode: '123456' }; // 关键:Mock控制器实际调用的findVendor函数,而非Vendor.find jest.spyOn(await import('../../services/vendorService'), 'findVendor').mockResolvedValueOnce(null); jest.spyOn(Vendor, 'create').mockResolvedValueOnce(mockVendorData); const res = await request(app) .post('/admin/vendor') .send(mockVendorData) .expect(201); // 验证响应数据 expect(res.body.success.name).toBe(mockVendorData.name); expect(res.body.success.email).toBe(mockVendorData.email); // 验证mock函数调用情况 expect(generateSalt).toHaveBeenCalledTimes(1); expect(hashPassword).toHaveBeenCalledWith(mockVendorData.password, 'test-salt'); expect(findVendor).toHaveBeenCalledWith('', mockVendorData.email); }); });
关键检查点
- 路由匹配:确保
POST /admin/vendor是控制器的正确注册路径,测试用app已挂载该路由 - Mock目标准确:控制器调用的是
findVendor,必须Mock这个自定义函数,而非Vendor.find - 独立函数Mock方式:对于独立导出的工具函数,必须用
jest.mockMock整个模块,不能用jest.spyOn
内容的提问来源于stack exchange,提问作者Haris Bukhari
相关产品推荐
相关产品推荐

