Jest 测试 React Redux 异步 action encounter 的问题

在使用 React 和 Redux 构建大型应用程序时,经常会遇到需要处理异步数据的情况。为了测试异步 action 是否正确执行和返回期望的结果,我们可以使用 Jest 测试框架。

然而,在实践中,测试异步 action 可能会遇到一些问题。本文将探讨这些问题以及如何解决它们。

问题 1:异步 action 在测试中如何处理?

首先,我们需要明确一个问题:在 Redux 中,我们可以使用 action creators 来创建 action,然后使用 middleware 来处理异步行为。

对于常规的同步 action,我们可以轻松地测试它们。但是对于异步 action,测试就变得更加复杂了。因为异步 action 必须等待异步操作完成后才能返回 action。

为了处理异步 action,我们使用了 redux-mock-store 库创建了一个模拟 store。通过模拟 store,我们可以捕获 action 并测试相应的 reducer 是否正确处理它们。

下面是一个简单的示例:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import { fetchUsers } from './users';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

describe('async actions', () => {
  it('creates FETCH_USERS_SUCCESS when fetching users has been done', () => {
    const expectedActions = [
      { type: 'FETCH_USERS_REQUEST' },
      { type: 'FETCH_USERS_SUCCESS', payload: [{ id: 1, name: 'John' }] },
    ];
    const store = mockStore({ users: [] });

    return store.dispatch(fetchUsers()).then(() => {
      expect(store.getActions()).toEqual(expectedActions)
    });
  });
});

在这个示例中,我们创建了一个模拟 store,并使用 redux-thunk middleware 处理异步 action。通过 dispatch(fetchUsers()),我们触发了异步 action。在 actions 文件中,fetchUsers() 返回了一个包含请求结果的 Promise。

在测试中,我们可以使用 expect() 检查期望的 action 是否正确生成,并使用 getActions() 方法获取 store 接收到的所有 action。最后,我们使用 toEqual() 比较期望和实际值是否相等。

问题 2:如何处理网络请求?

在测试异步 action 时,经常需要模拟网络请求以便测试异步行为。

Jest 提供了一个强大的工具:Jest Mock。使用 Jest Mock 可以模拟外部依赖,并使测试的速度更快。

在我们的示例中,我们假设我们正在通过 axios 库从 API 中获取数据。在测试中,我们不想真正发出网络请求,因此要进行模拟。

我们使用 Jest Mock 来模拟 axios 库。这使我们可以使用 fake data 来代替真实的 API 响应,并且我们可以控制测试中返回的数据。

下面是使用 Jest Mock 来模拟 axios 库的示例代码:

import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { fetchUsers } from './users';

describe('async actions', () => {
  it('creates FETCH_USERS_SUCCESS when fetching users has been done', () => {
    const mock = new MockAdapter(axios);
    const expectedUsers = [{ id: 1, name: 'John' }];
    mock.onGet('/users').reply(200, expectedUsers);

    const expectedActions = [
      { type: 'FETCH_USERS_REQUEST' },
      { type: 'FETCH_USERS_SUCCESS', payload: expectedUsers },
    ];

    const store = mockStore({ users: [] });

    return store.dispatch(fetchUsers()).then(() => {
      expect(store.getActions()).toEqual(expectedActions);
    });
  });
});

在这个示例中,我们创建了一个 MockAdapter 对象,并将其与 axios 实例连接。mock.onGet() 方法模拟了 GET 请求,并返回 fake data。

在 action creator 中,我们使用 axios 库发出请求,实际上执行的是 MockAdapter 对象的模拟请求。

问题 3:如何测试异步 action 中的错误处理?

在异步 action 中,我们通常需要添加错误处理逻辑,以处理请求失败的情况。为了测试这些错误情况,我们需要将模拟的 store 改为返回错误的 action。

下面是一个处理错误的示例代码:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import axios from 'axios';
import MockAdapter from 'axios-mock-adapter';
import { fetchUsers } from './users';

const middlewares = [thunk];
const mockStore = configureMockStore(middlewares);

describe('async actions', () => {
  it('creates FETCH_USERS_FAILURE when fetching users fails', () => {
    const mock = new MockAdapter(axios);
    mock.onGet('/users').reply(500);

    const expectedActions = [
      { type: 'FETCH_USERS_REQUEST' },
      { type: 'FETCH_USERS_FAILURE', payload: 'Request failed with status code 500' },
    ];

    const store = mockStore({ users: [] });

    return store.dispatch(fetchUsers()).then(() => {
      expect(store.getActions()).toEqual(expectedActions);
    });
  });
});

在这个示例中,我们使用 MockAdapter 模拟了一个 HTTP POST 请求,并返回了一个错误响应。

接下来,我们创建了一个期望的 action 数组,包含一个 FETCH_USERS_REQUEST 和一个 FETCH_USERS_FAILURE action。在错误情况下,fetchUsers() action creator 返回了一个包含错误消息的 Promise。

在测试中,我们检查 store 是否已正确处理错误情况,并检查传递给 FETCH_USERS_FAILURE action 的错误消息是否正确。

总结

在本文中,我们学习了如何在 Jest 中测试异步 action,以及如何解决测试过程中遇到的常见问题。我们了解了如何使用 redux-mock-store 库来创建模拟 store,如何使用 Jest Mock 模拟网络请求,以及如何测试异步 action 中的错误处理。

通过这些实践,我们可以更好地理解测试异步 action 的过程,并在实际开发中更加轻松地处理相关问题。

来源:JavaScript中文网 ,转载请注明来源 本文地址:https://www.javascriptcn.com/post/65b39f04add4f0e0ffca9c88