[英]How do I test axios in Jest?
我在 React 中有這個動作:
export function fetchPosts() {
const request = axios.get(`${WORDPRESS_URL}`);
return {
type: FETCH_POSTS,
payload: request
}
}
在這種情況下如何測試Axios ?
Jest 在他們的網站上有這個用例,用於異步代碼,他們使用模擬函數,但我可以用 Axios 做到這一點嗎?
參考:一個異步示例
到目前為止,我已經這樣做了以測試它是否返回了正確的類型:
it('should dispatch actions with the correct type', () => {
store.dispatch(fetchPosts());
let action = store.getActions();
expect(action[0].type).toBe(FETCH_POSTS);
});
如何傳入模擬數據並測試它是否返回?
不使用任何其他庫:
import * as axios from "axios";
// Mock out all top level functions, such as get, put, delete and post:
jest.mock("axios");
// ...
test("good response", () => {
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
// ...
});
test("bad response", () => {
axios.get.mockImplementation(() => Promise.reject({ ... }));
// ...
});
可以指定響應代碼:
axios.get.mockImplementation(() => Promise.resolve({ status: 200, data: {...} }));
可以根據參數更改模擬:
axios.get.mockImplementation((url) => {
if (url === 'www.example.com') {
return Promise.resolve({ data: {...} });
} else {
//...
}
});
Jest v23 引入了一些用於模擬 Promises 的語法糖:
axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));
它可以簡化為
axios.get.mockResolvedValue({ data: {...} });
被拒絕的承諾也有一個等價物: mockRejectedValue
。
延伸閱讀:
jest.mock("axios")
行的范圍。mockImplementation
類的笑話函數: Typescript 和 Jest:避免模擬函數上的類型錯誤我使用了 axios-mock-adapter 。 在這種情況下,服務在 ./chatbot 中進行了描述。 在模擬適配器中,您指定使用 API 端點時要返回的內容。
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import chatbot from './chatbot';
describe('Chatbot', () => {
it('returns data when sendMessage is called', done => {
var mock = new MockAdapter(axios);
const data = { response: true };
mock.onGet('https://us-central1-hutoma-backend.cloudfunctions.net/chat').reply(200, data);
chatbot.sendMessage(0, 'any').then(response => {
expect(response).toEqual(data);
done();
});
});
});
你可以在這里看到整個例子:
服務: https ://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.js
測試: https ://github.com/lnolazco/hutoma-test/blob/master/src/services/chatbot.test.js
我可以按照以下步驟進行操作:
axios.js
模擬文件模擬將自動發生
模擬模塊示例:
module.exports = {
get: jest.fn((url) => {
if (url === '/something') {
return Promise.resolve({
data: 'data'
});
}
}),
post: jest.fn((url) => {
if (url === '/something') {
return Promise.resolve({
data: 'data'
});
}
if (url === '/something2') {
return Promise.resolve({
data: 'data2'
});
}
}),
create: jest.fn(function () {
return this;
})
};
我已經用nock完成了這個,就像這樣:
import nock from 'nock'
import axios from 'axios'
import httpAdapter from 'axios/lib/adapters/http'
axios.defaults.adapter = httpAdapter
describe('foo', () => {
it('bar', () => {
nock('https://example.com:443')
.get('/example')
.reply(200, 'some payload')
// test...
})
})
看這個
album.js
的函數const fetchAlbum = function () {
return axios
.get("https://jsonplaceholder.typicode.com/albums/2")
.then((response) => {
return response.data;
});
};
album.test.js
const axios = require("axios");
const { fetchAlbum } = require("../utils.js");
jest.mock("axios");
test("mock axios get function", async () => {
expect.assertions(1);
const album = {
userId: 1,
id: 2,
title: "sunt qui excepturi placeat culpa",
};
const payload = { data: album };
// Now mock axios get method
axios.get = jest.fn().mockResolvedValue(payload);
await expect(fetchAlbum()).resolves.toEqual(album);
});
對於那些希望使用 axios-mock-adapter 代替Redux文檔中的 mockfetch 示例進行異步測試的人,我成功地使用了以下內容:
describe('SignInUser', () => {
var history = {
push: function(str) {
expect(str).toEqual('/feed');
}
}
it('Dispatches authorization', () => {
let mock = new MockAdapter(axios);
mock.onPost(`${ROOT_URL}/auth/signin`, {
email: 'test@test.com',
password: 'test'
}).reply(200, {token: 'testToken' });
const expectedActions = [ { type: types.AUTH_USER } ];
const store = mockStore({ auth: [] });
return store.dispatch(actions.signInUser({
email: 'test@test.com',
password: 'test',
}, history)).then(() => {
expect(store.getActions()).toEqual(expectedActions);
});
});
為了在文件actions/index.js中測試signInUser
的成功案例:
export const signInUser = ({ email, password }, history) => async dispatch => {
const res = await axios.post(`${ROOT_URL}/auth/signin`, { email, password })
.catch(({ response: { data } }) => {
...
});
if (res) {
dispatch({ type: AUTH_USER }); // Test verified this
localStorage.setItem('token', res.data.token); // Test mocked this
history.push('/feed'); // Test mocked this
}
}
鑒於這是通過開玩笑來完成的,因此必須模擬 localstorage 調用。 這是在文件src/setupTests.js 中:
const localStorageMock = {
removeItem: jest.fn(),
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;
自從最初回答了這個問題以來,已經引入了新的測試工具。
模擬的問題在於您經常測試模擬而不是代碼的真實上下文,從而使該上下文的某些區域未經測試。 對告訴 axios 返回什么承諾的改進是通過 Service Worker 攔截 http 請求。
Service Worker是您的 Web 應用程序和外部世界之間的客戶端可編程代理。 因此,與其模擬承諾解決方案,不如模擬代理服務器本身,攔截要測試的請求,這是一個更廣泛的解決方案。 由於攔截發生在網絡級別,您的應用程序對模擬一無所知。
您可以使用msw ( Mock Service Worker ) 庫來做到這一點。 這是一個簡短的視頻,解釋了它是如何工作的。
我能想到的最基本的設置是這樣的: 1️⃣
設置handlers,類似於express.js的路由方法; 2️⃣
設置模擬服務器並將處理程序作為參數傳遞; 3️⃣
配置測試,以便模擬服務器攔截我們的請求; 4️⃣
進行測試; 5️⃣
關閉模擬服務器。
假設您要測試以下功能:
import axios from "axios";
export const fetchPosts = async () => {
const request = await axios.get("/some/endpoint/");
return {
payload: request,
};
};
然后測試可能如下所示:
import { rest } from "msw";
import { setupServer } from "msw/node";
import fetchPosts from "./somewhere";
// handlers are usually saved in separate file(s) in one destined place of the app,
// so that you don't have to search for them when the endpoints have changed
const handlers = [ 1️⃣
rest.get("/some/endpoint/", (req, res, ctx) =>
res(ctx.json({ message: "success" }))
),
];
const server = setupServer(...handlers); 2️⃣
beforeAll(() => {
server.listen(); 3️⃣
});
describe("fetchPosts", () => {
it("should return 'success' message", async () => {
const resp = await fetchPosts();
expect(resp.payload?.data?.message).toEqual("success"); 4️⃣
});
});
afterAll(() => {
server.close(); 5️⃣
});
根據您使用的框架,配置可能會有所不同。 可以在 MSW 的repo上找到 React(REST 和 GraphQL)和 Angular 等一些通用示例。 VueMastery提供了一個 Vue 示例。 您還可以在 MSW 的食譜頁面上找到示例。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.