如何在 Jest 中测试 Axios?

我在《反应:

export function fetchPosts() {
const request = axios.get(`${WORDPRESS_URL}`);
return {
type: FETCH_POSTS,
payload: request
}
}

在这种情况下,我如何测试 Axios

Jest 在他们的站点上有一个异步代码的用例,他们使用一个模拟函数,但是我可以用 Axios 做到这一点吗?

参考资料: 一个 Async 示例

到目前为止,我这样做是为了测试它是否返回了正确的类型:

it('should dispatch actions with the correct type', () => {
store.dispatch(fetchPosts());
let action = store.getActions();
expect(action[0].type).toBe(FETCH_POSTS);
});

如何传入模拟数据并测试它是否返回?

228831 次浏览

我用的是 轴模拟适配器轴模拟适配器。 在这种情况下,服务在./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

我用 敲门做过这个,就像这样:

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...
})
})

我可以按照下面的步骤来做:

  1. 创建一个文件夹 嘲笑(如@Januartha 注释所指出的)
  2. 实现一个 axios.js模拟文件
  3. 测试上使用我实现的模块

模拟将自动发生

模拟模块示例:

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;
})
};

对于那些希望在 复制文档 进行异步测试中使用 axios-mock-Adapter 来代替仿冒获取示例的人,我成功地使用了以下内容:

文件 Actions.test.js:

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
}
}

假设这是通过 jest 完成的,那么本地存储调用必须被模拟:

const localStorageMock = {
removeItem: jest.fn(),
getItem: jest.fn(),
setItem: jest.fn(),
clear: jest.fn()
};
global.localStorage = localStorageMock;

不使用任何其他库:

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引入了一些语法糖来嘲笑承诺:

axios.get.mockImplementation(() => Promise.resolve({ data: {...} }));

它可以简化为

axios.get.mockResolvedValue({ data: {...} });

对于被拒绝的承诺也有一个等价物: mockRejectedValue

进一步阅读:

看看这个

  1. 测试 album.js的函数
const fetchAlbum = function () {
return axios
.get("https://jsonplaceholder.typicode.com/albums/2")
.then((response) => {
return response.data;
});
};
  1. 测试 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);
});

自从这个问题最初得到回答以来,已经引入了新的测试工具。

模仿的问题在于,您经常测试的是模仿,而不是代码的真实上下文,这使得该上下文的某些区域未经测试。 通过 ServiceWorkers 拦截 http 请求比告诉 Axios 承诺返回的内容更好。

Service worker 是一个客户端的可编程代理,它介于你的 web 应用和外部世界之间。因此,与模仿承诺解决方案相比,模仿代理服务器本身、拦截要测试的请求是一个更广泛的解决方案。由于拦截发生在网络级别,因此您的应用程序不知道任何有关嘲弄的信息。

你可以使用 医学博士(模拟服务员)库来实现这一点。

我能想到的最基本的设置是这样的: 1️⃣设置处理程序,类似于 Express.js 路由方法; 2️⃣设置模拟服务器并将处理程序作为参数传递; 3️⃣配置测试,以便模拟服务器将拦截我们的请求; 4️⃣执行测试; 关闭模拟服务器。

假设您想测试以下特性:

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 的 回购中可以找到一些反应(REST 和 GraphQL)和角度的一般例子。VueMaster提供了一个 Vue 示例。 你也可以在 MSW 的 食谱页上找到例子。