You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.18 19:14:51