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

如何测试Express.js ErrorHandler?求助TypeScript+Sinon函数失败案例测试方法

测试findById函数的失败场景(TypeScript + Sinon)

你的findById函数失败场景核心是:当findByPk返回null时,抛出NotFound错误。用Sinon可以轻松模拟findByPk的返回值,结合断言库验证错误是否正确抛出。

测试步骤与代码示例

假设你使用Mocha作为测试框架、Chai(搭配chai-as-promised)作为断言库,示例代码如下:

import { expect } from 'chai';
import sinon from 'sinon';
import { UserService } from './user.service'; // 替换为你的服务类路径
import { NotFound } from './errors'; // 替换为你的错误类路径
import { UserModel } from './user.model'; // 替换为你的模型类路径

describe('UserService.findById', () => {
  let userService: UserService;
  let findByPkStub: sinon.SinonStub;

  beforeEach(() => {
    // 模拟UserModel的findByPk方法
    findByPkStub = sinon.stub(UserModel, 'findByPk');
    // 初始化服务实例(如果服务依赖模型,按需注入)
    userService = new UserService();
  });

  afterEach(() => {
    // 恢复被stub的方法,避免影响其他测试
    findByPkStub.restore();
  });

  it('抛出NotFound错误当用户不存在时', async () => {
    // 让findByPk返回null
    findByPkStub.resolves(null);

    // 验证异步函数是否抛出指定错误
    await expect(userService.findById(999)).to.be.rejectedWith(NotFound, 'User not found');
    // 验证stub被正确调用
    expect(findByPkStub.calledOnceWith(999)).to.be.true;
  });
});

核心要点

  • 用sinon.stub替换模型的findByPk方法,通过resolves(null)模拟异步返回空值
  • 使用chai-as-promised的rejectedWith断言异步函数的错误类型与消息
  • 验证stub的调用情况,确保代码走对了分支

测试Express.js的错误处理器

Express错误处理器是接收err, req, res, next四个参数的中间件,测试时需要模拟请求、响应对象,验证处理器对不同错误的处理逻辑。

先假设你的错误处理器实现

// error-handler.ts
import { Request, Response, NextFunction } from 'express';
import { NotFound } from './errors';

export const errorHandler = (err: Error, req: Request, res: Response, next: NextFunction) => {
  if (err instanceof NotFound) {
    return res.status(404).json({ message: err.message });
  }

  // 兜底处理未知错误
  res.status(500).json({ message: 'Internal server error' });
};

测试代码示例

import { expect } from 'chai';
import sinon from 'sinon';
import { errorHandler } from './error-handler';
import { NotFound } from './errors';
import { Request, Response } from 'express';

describe('errorHandler', () => {
  let req: Partial<Request>;
  let res: Partial<Response>;
  let statusStub: sinon.SinonStub;
  let jsonStub: sinon.SinonStub;

  beforeEach(() => {
    req = {};
    // 模拟res的链式调用:res.status().json()
    jsonStub = sinon.stub().returnsThis();
    statusStub = sinon.stub().returns({ json: jsonStub } as Partial<Response>);
    res = { status: statusStub };
  });

  it('处理NotFound错误:返回404状态码与对应消息', () => {
    const notFoundErr = new NotFound('User not found');

    errorHandler(notFoundErr, req as Request, res as Response, sinon.spy());

    expect(statusStub.calledOnceWith(404)).to.be.true;
    expect(jsonStub.calledOnceWith({ message: 'User not found' })).to.be.true;
  });

  it('处理未知错误:返回500状态码与通用消息', () => {
    const genericErr = new Error('Unexpected error');

    errorHandler(genericErr, req as Request, res as Response, sinon.spy());

    expect(statusStub.calledOnceWith(500)).to.be.true;
    expect(jsonStub.calledOnceWith({ message: 'Internal server error' })).to.be.true;
  });
});

核心要点

  • 用Sinon模拟res.status和res.json方法,通过链式stub实现Express的调用逻辑(status返回res自身,所以让stub返回包含json stub的对象)
  • 针对不同错误类型分别测试,验证状态码和返回的JSON内容是否符合预期
  • 无需调用next,错误处理器是请求链的最后一步

内容的提问来源于stack exchange,提问作者Vinicius Bortoletto

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.30 04:37:43