Express.js应用中使用Jest模拟Axios调用失败,求解决方案
如何在Jest中模拟Express应用的Axios第三方调用
你的测试失败主要源于几个关键问题,下面逐一分析并给出修正方案:
问题分析
- Axios模拟结构错误:Axios的
get方法返回的响应是包含data字段的对象,你直接将用户数据传给mockResolvedValueOnce,导致controller中response.data取不到有效值。 - 响应数据断言位置错误:supertest返回的接口响应数据存储在
res.body属性中,直接断言res.id、res.role会得到undefined。 - Express响应写法错误:
res.send(...).status(200)的链式调用顺序有误,status()需放在send()之前,否则无法正确设置HTTP状态码。 - 错误处理缺失:controller中未在catch块返回错误响应,会导致测试时请求因未完成而挂起。
修正后的代码
controller.js
const axios = require('axios'); const baseUrl = "Some 3rd party url"; const getUser = async (req, res) => { let url = baseUrl + '/user'; try { // 改用async/await让代码更简洁易读 const response = await axios.get(url); // 先设置状态码再发送响应 res.status(200).send(response.data); } catch (error) { console.log(error); // 添加错误响应,避免请求挂起 res.status(500).send('Error fetching user'); } }; module.exports = { getUser };
test.js
const axios = require('axios'); const supertest = require('supertest'); const app = require('../server'); const request = supertest(app); jest.mock("axios"); const baseUrl = "Some 3rd party url"; describe("GET /user", () => { it("should return a user successfully", async () => { // Given const mockUser = { id: "1234567", role: "Test" }; // 模拟Axios真实响应结构:包含data字段 axios.get.mockResolvedValueOnce({ data: mockUser }); // When const res = await request.get('/user'); // Then expect(axios.get).toHaveBeenCalledWith(`${baseUrl}/user`); expect(res.statusCode).toBe(200); // 从res.body中获取接口返回的JSON数据 expect(res.body.id).toBe("1234567"); expect(res.body.role).toBe("Test"); }); it("should return 500 error when fetching user fails", async () => { // Given axios.get.mockRejectedValueOnce(new Error('Third party API failure')); // When const res = await request.get('/user'); // Then expect(axios.get).toHaveBeenCalledWith(`${baseUrl}/user`); expect(res.statusCode).toBe(500); expect(res.text).toBe('Error fetching user'); }); });
关键修正说明
- Axios模拟结构:按照Axios真实响应格式,用
{ data: mockData }作为mock返回值,确保controller能正确解析数据。 - 响应断言方式:通过
res.body访问接口返回的JSON内容,这是supertest获取响应数据的标准方式。 - 响应顺序调整:先调用
res.status()设置状态码,再调用res.send()发送响应,确保状态码生效。 - 完善错误处理:在controller的catch块中添加错误响应,避免测试时请求因未完成而超时。
- 补充错误测试:新增失败场景的测试用例,让测试覆盖正常和异常两种情况,保证代码健壮性。
内容的提问来源于stack exchange,提问作者ankit lohiya
相关产品推荐
相关产品推荐

