Node.js中Jest中间件测试用例编写及报错排查
问题排查与解决方案
错误根源分析
报错TypeError: (0 , validatePathParametr_1.validatePathParametr) is not a function的核心原因是Jest的模块mock覆盖了整个导出对象,但未包含被测试的validatePathParametr函数,导致测试代码中导入的该函数为undefined。此外还有其他语法和逻辑错误:
- Jest mock仅导出了
validateId和validateName,遗漏了validatePathParametr - 测试代码存在变量名错误:
validateCluster应为validateId,console.log中的validateParams未定义 - 原中间件有语法错误:
validateName(name)\末尾的多余反斜杠、解构{ id, name, }的多余逗号 - 测试断言逻辑错误:比如断言
validateId被调用时传入'2',但测试请求的id是11
修复后的中间件代码
先修正原中间件的语法问题:
import { Request, Response, NextFunction } from 'express'; // 替换为实际的日志模块导入路径 import getLogger from './logger'; export const validatePathParametr = (req: Request, res: Response, next: NextFunction): void => { // 移除多余逗号 const { id, name } = req.params; try { validateId(id); // 移除多余反斜杠 validateName(name); } catch (error: any) { error.msg = 'wrong parameter'; error.code = 500; getLogger().error({ req, error, }); return next(error); } return next(); }; // 导出内部函数方便测试 export function validateId(id: unknown) { if (!id || id === null) { throw new Error(`id cannot be empty`); } } export function validateName(name: unknown) { if (!name || name === null) { throw new Error(`name cannot be empty`); } }
正确的Jest测试用例
修改测试代码,确保mock保留被测试的中间件,同时修正变量和断言错误:
import { createRequest, createResponse } from 'node-mocks-http'; import { validatePathParametr, validateId, validateName } from '../../validatePathParameter'; // 保留原模块导出,仅mock内部验证函数 jest.mock('../../validatePathParameter', () => { const originalModule = jest.requireActual('../../validatePathParameter'); return { ...originalModule, validateId: jest.fn(), validateName: jest.fn(), }; }); describe.only('validatePathParametr Middleware', () => { let mockRequest: any; let mockResponse: any; let next: jest.Mock; beforeEach(() => { // 路径参数默认是字符串,改为符合真实场景的类型 mockRequest = createRequest({ params: { id: '11', name: 'test' } }); mockResponse = createResponse(); next = jest.fn(); jest.clearAllMocks(); }); it('should call validateId, validateName and invoke next on success', () => { // 模拟验证函数不抛出错误 (validateId as jest.Mock).mockImplementation(() => {}); (validateName as jest.Mock).mockImplementation(() => {}); validatePathParametr(mockRequest, mockResponse, next); // 匹配实际传入的参数值 expect(validateId).toHaveBeenCalledWith('11'); expect(validateName).toHaveBeenCalledWith('test'); expect(next).toHaveBeenCalledTimes(1); expect(next).toHaveBeenCalledWith(); }); it('should call next with formatted error when validateId fails', () => { const errorMessage = 'id cannot be empty'; (validateId as jest.Mock).mockImplementation(() => { throw new Error(errorMessage); }); validatePathParametr(mockRequest, mockResponse, next); // 验证错误被正确格式化 expect(next).toHaveBeenCalledWith(expect.any(Error)); const passedError = next.mock.calls[0][0]; expect(passedError.message).toBe(errorMessage); expect(passedError.msg).toBe('wrong parameter'); expect(passedError.code).toBe(500); }); it('should call next with formatted error when validateName fails', () => { const errorMessage = 'name cannot be empty'; (validateId as jest.Mock).mockImplementation(() => {}); (validateName as jest.Mock).mockImplementation(() => { throw new Error(errorMessage); }); validatePathParametr(mockRequest, mockResponse, next); expect(next).toHaveBeenCalledWith(expect.any(Error)); const passedError = next.mock.calls[0][0]; expect(passedError.message).toBe(errorMessage); expect(passedError.msg).toBe('wrong parameter'); expect(passedError.code).toBe(500); }); });
关键修复点说明
- 模块Mock方式:使用
jest.requireActual保留原模块导出,仅mock内部验证函数,避免覆盖被测试的中间件 - 变量名修正:将
validateCluster改为validateId,移除未定义的validateParams日志 - 类型修正:路径参数默认是字符串,调整测试请求的id类型符合真实场景
- 断言逻辑修正:匹配实际传入的参数值,同时验证错误对象的格式化属性
- 语法错误修复:移除原中间件中的多余逗号和反斜杠
内容的提问来源于stack exchange,提问作者user13000875
相关产品推荐
相关产品推荐

