Node.js异步函数getSomeTask的Jest单元测试编写求助
修正后的Jest单元测试方案
一、先修正__mocks__/request.js
request库的get方法是基于回调的,mock函数需要支持触发传入的回调,所以修改为:
function get(options, callback) { // 留空让测试代码动态定义回调逻辑 callback(); return this; } module.exports = { get };
二、完整的Jest测试代码
const handler = require("../../handler"); const request = require("request"); // 告诉Jest使用mock版本的request模块 jest.mock("request"); describe("getSomeTask 函数测试", () => { // 每个测试前重置mock调用记录 beforeEach(() => { jest.clearAllMocks(); }); it("请求成功时,返回200状态和响应体", (done) => { // 模拟成功的响应数据 const mockResponseBody = JSON.stringify({ Test: "test" }); const mockResponse = { statusCode: 200 }; // 模拟request.get触发成功回调 request.get.mockImplementation((options, callback) => { callback(mockResponse, mockResponseBody); return {}; }); // 模拟res对象的方法,跟踪调用情况 const res = { writeHead: jest.fn(), write: jest.fn(), end: jest.fn(), status: jest.fn().mockReturnThis(), // 支持链式调用,返回自身 json: jest.fn() }; // 调用目标函数 handler.getSomeTask(res); // 等待异步回调执行完成后断言 setTimeout(() => { // 验证request.get是否以正确的参数调用 expect(request.get).toHaveBeenCalledWith( { url: "http://example.com" }, // 替换为实际的someTaskUrl值 expect.any(Function) ); // 验证响应方法的调用正确性 expect(res.writeHead).toHaveBeenCalledWith(200, { 'content-type': 'application/json' }); expect(res.write).toHaveBeenCalledWith(mockResponseBody); expect(res.end).toHaveBeenCalled(); // 验证错误分支方法未被调用 expect(res.status).not.toHaveBeenCalled(); expect(res.json).not.toHaveBeenCalled(); done(); }, 0); }); it("请求失败时,返回400错误", (done) => { // 模拟失败的响应 const mockResponse = { statusCode: 500 }; // 模拟request.get触发失败回调 request.get.mockImplementation((options, callback) => { callback(mockResponse, null); return {}; }); // 模拟res对象 const res = { writeHead: jest.fn(), write: jest.fn(), end: jest.fn(), status: jest.fn().mockReturnThis(), json: jest.fn() }; handler.getSomeTask(res); setTimeout(() => { // 验证错误响应的调用正确性 expect(res.status).toHaveBeenCalledWith(400); expect(res.json).toHaveBeenCalledWith({ error: 'Failed' }); // 验证成功分支方法未被调用 expect(res.writeHead).not.toHaveBeenCalled(); expect(res.write).not.toHaveBeenCalled(); expect(res.end).not.toHaveBeenCalled(); done(); }, 0); }); });
三、关键问题说明
原函数的异步处理问题
虽然getSomeTask声明了async,但内部用的是request的回调模式,没有返回Promise,所以测试不能用await,必须用done参数让Jest等待异步回调执行完成。如果想改用await,可以用util.promisify把request.get包装成Promise形式。Mock request的正确姿势
- 不需要直接引用
__mocks__里的模块,jest.mock("request")会自动替换为mock版本。 - 必须模拟回调触发:request.get是回调式API,mock时要主动调用传入的callback,传入预设的响应数据。
- 不需要直接引用
Res对象的mock技巧
- 给res的每个方法创建jest mock函数,用于跟踪调用记录和参数。
- 对于Express风格的链式调用(如
res.status().json()),需要让status方法返回res自身,用mockReturnThis()实现。
原测试代码的错误点
- 原测试里的
jest.fn().mockImplementation(...)没有赋值给request.get,完全无效。 - 空的
res对象没有模拟所需方法,调用时会直接报错。 - 没有处理异步回调,测试会提前结束,导致断言失败。
- 原测试里的
内容的提问来源于stack exchange,提问作者sonny
相关产品推荐
相关产品推荐

