如何使用Jest模拟Express的Response.setHeader函数以测试自定义中间件
如何使用Jest模拟Express的Response.setHeader函数以测试自定义中间件
我懂你现在卡在哪了——你在mock Express的Response对象时,setHeader的实现触发了递归调用,导致报错this.setHeader is not a function。这是因为你在mock的setHeader里试图调用this.setHeader,但这个mock对象本身没有真正的setHeader方法,相当于自己调用自己,自然会出错。而且你还需要后续断言响应的Content-Type,所以得给mock对象加个存储headers的地方才行。
下面是修正后的测试代码,我会一步步给你解释逻辑:
首先,我们要给mockResponse加一个headers对象用来存设置的头信息,重写setHeader的mock实现把键值对存进去;同时添加getHeader的mock函数,从这个对象里取值。另外别忘了给mockResponse加上statusCode属性,因为你的中间件会直接给它赋值。
it("responds with status code 415 if header 'Content-Type' is not 'application/json'.", () => { const contentType = "multipart/form-data"; // 模拟Request对象,和你原来的实现一致 const mockRequest: Partial<Request> = { headers: { "Content-Type": contentType, }, is: jest.fn().mockReturnValue(false), get: jest.fn().mockReturnValue(contentType), }; // 修正后的Response mock核心部分 const mockResponse: Partial<Response> = { statusCode: 200, // 初始值,中间件会修改为415 headers: {}, // 用来存储设置的响应头 setHeader: jest.fn((name, value) => { // 把设置的头信息存入mock的headers对象 (mockResponse.headers as Record<string, string>)[name] = value; }), getHeader: jest.fn((name) => { // 从mock的headers对象中取值,支持后续断言 return (mockResponse.headers as Record<string, string>)[name]; }), json: jest.fn(), }; const nextFunction: NextFunction = jest.fn(); const expectedResponse = { isSuccessful: false, error: `Expected Content-Type 'application/json' but got '${contentType}'.`, }; const middleware = enforceContentTypeApplicationJson(); middleware(mockRequest as Request, mockResponse as Response, nextFunction); // 断言状态码是否正确设置为415 expect(mockResponse.statusCode).toBe(415); // 断言响应Content-Type是否被设置为application/json expect(mockResponse.getHeader).toHaveBeenCalledWith('Content-Type'); expect(mockResponse.getHeader('Content-Type')).toBe('application/json'); // 断言错误响应体是否正确返回 expect(mockResponse.json).toHaveBeenCalledWith(expectedResponse); // 断言next函数未被调用(因为中间件直接返回了错误响应) expect(nextFunction).not.toHaveBeenCalled(); });
关键修正点说明:
- 新增
headers对象:模拟真实Response存储头信息的行为,让setHeader和getHeader有可以操作的数据源。 - 重写
setHeader实现:不再递归调用自己,而是直接将头信息存入mockResponse.headers。 - 添加
getHeader函数:方便后续断言响应头是否符合预期。 - 新增
nextFunction断言:确保中间件在返回错误响应时,不会继续执行后续逻辑,这是测试中间件完整性的重要环节。
如果之后要测试Content-Type符合要求的场景,只需要把mockRequest.is的返回值改成true,然后断言nextFunction被调用即可。
备注:内容来源于stack exchange,提问作者baitendbidz
相关产品推荐
相关产品推荐

