使用axios-mock-adapter测试时POST请求报404错误排查
问题:Axios Mock Adapter POST请求测试返回404,GET请求正常
在Vue项目中使用Vitest运行单元测试时,通过axios-mock-adapter测试自定义Axios实例,GET请求测试能通过,但POST请求始终返回Request failed with status code 404错误。
原Axios实例代码(default.js)
import axios from "axios"; const BASE_URL = import.meta.env.VITE_BACKEND_BASE_URL; const instance = axios.create({ baseURL: BASE_URL, }); instance.defaults.headers.common["Accept"] = "application/json"; instance.defaults.headers.post["Content-Type"] = "application/json"; instance.interceptors.request.use( function (config) { config.headers.Authorization = localStorage.getItem("token"); return config; }, function (error) { return Promise.reject(error); } ); export default instance;
原单元测试代码(default.test.js)
import MockAdapter from "axios-mock-adapter"; import axios from "@/axios/default"; describe("Axios functions", () => { let mock; beforeEach(() => { mock = new MockAdapter(axios); }); it("sends a GET request to the endpoint", async () => { const endpoint = "/example"; const url = import.meta.env.VITE_BACKEND_BASE_URL + endpoint; const token = "12345"; const expectedData = { example: "data" }; mock .onGet(url, { headers: { Authorization: token, Accept: "application/json" }, }) .reply(200, expectedData); localStorage.setItem("token", token); const response = await axios.get(endpoint); expect(mock.history.get.length).toBe(1); expect(mock.history.get[0].url).toBe(endpoint); expect(mock.history.get[0].headers.Authorization).toBe(token); expect(mock.history.get[0].headers.Accept).toBe("application/json"); expect(response.data).toEqual(expectedData); }); it("sends a POST request to the endpoint", async () => { const endpoint = "/example"; const url = import.meta.env.VITE_BACKEND_BASE_URL + endpoint; const token = "12345"; const postData = { example: "data" }; const expectedData = { success: true }; mock .onPost(url, postData, { headers: { Authorization: token, "Content-Type": "application/json", Accept: "application/json", }, }) .reply(200, expectedData); localStorage.setItem("token", token); const response = await axios.post(endpoint, postData); expect(mock.history.post.length).toBe(1); expect(mock.history.post[0].url).toBe(endpoint); expect(mock.history.post[0].headers.Authorization).toBe(token); expect(mock.history.post[0].headers["Content-Type"]).toBe( "application/json" ); expect(mock.history.post[0].headers.Accept).toBe("application/json"); expect(JSON.parse(mock.history.post[0].data)).toEqual(postData); expect(response.data).toEqual(expectedData); }); });
报错原因分析
- URL匹配冗余:自定义Axios实例已配置
baseURL,调用axios.post(endpoint)时,mock适配器会自动拼接baseURL,无需手动拼接完整URL进行匹配,否则会导致URL不匹配。 - POST数据匹配问题:Axios会自动将POST请求的对象数据序列化为JSON字符串,但mock时直接传入原始对象
postData,导致适配器无法匹配到对应的请求。 - Headers严格匹配冲突:
onPost的第三个参数是严格匹配headers,但Axios可能会自动添加额外的headers字段,或者大小写处理差异,导致匹配失败。
解决方法及修改后的测试代码
针对上述问题,调整POST测试的mock逻辑:
- 直接使用
endpoint作为mock的URL,无需拼接baseURL - 用
JSON.stringify(postData)匹配序列化后的请求数据,或使用函数校验数据 - 简化headers匹配,只验证关键的
Authorization字段,避免严格匹配所有headers
修改后的测试代码:
import MockAdapter from "axios-mock-adapter"; import axios from "@/axios/default"; describe("Axios functions", () => { let mock; beforeEach(() => { mock = new MockAdapter(axios); }); it("sends a GET request to the endpoint", async () => { const endpoint = "/example"; const token = "12345"; const expectedData = { example: "data" }; // 直接使用endpoint匹配,无需拼接baseURL mock .onGet(endpoint, { headers: { Authorization: token } }) .reply(200, expectedData); localStorage.setItem("token", token); const response = await axios.get(endpoint); expect(mock.history.get.length).toBe(1); expect(mock.history.get[0].url).toBe(endpoint); expect(mock.history.get[0].headers.Authorization).toBe(token); expect(mock.history.get[0].headers.Accept).toBe("application/json"); expect(response.data).toEqual(expectedData); }); it("sends a POST request to the endpoint", async () => { const endpoint = "/example"; const token = "12345"; const postData = { example: "data" }; const expectedData = { success: true }; // 直接使用endpoint,匹配序列化后的data,简化headers匹配 mock .onPost(endpoint, JSON.stringify(postData), { headers: { Authorization: token } }) .reply(200, expectedData); localStorage.setItem("token", token); const response = await axios.post(endpoint, postData); expect(mock.history.post.length).toBe(1); expect(mock.history.post[0].url).toBe(endpoint); expect(mock.history.post[0].headers.Authorization).toBe(token); expect(mock.history.post[0].headers["Content-Type"]).toBe( "application/json" ); expect(mock.history.post[0].headers.Accept).toBe("application/json"); expect(JSON.parse(mock.history.post[0].data)).toEqual(postData); expect(response.data).toEqual(expectedData); }); });
另一种更灵活的方式是使用函数校验POST数据,避免序列化问题:
// 替换POST的mock部分 mock .onPost(endpoint, (data) => JSON.parse(data) === postData, { headers: { Authorization: token } }) .reply(200, expectedData);
内容的提问来源于stack exchange,提问作者Suyash Mittal
相关产品推荐
相关产品推荐

