【问题标题】:How Can I test a an action reducer with an async call and dispatch inside using Jest?如何使用 Jest 在内部使用异步调用和调度来测试 action reducer?
【发布时间】:2019-12-05 02:53:17
【问题描述】:

我是 Jest 的新手,我正在尝试对我的异步操作创建者进行测试。问题是我只看到了测试示例,其中有一个用于操作创建者的方法和其他用于调度的单独方法。我的动作创建者将调度作为异步回调函数,但我不知道如何进行测试。 我的 Action Reducer 如下所示:

export const postConnection = (connectionUrl, username, password) => {
    return async (dispatch) => {
        const response = await requireAuthActions.post('/db/conexion', JSON.stringify({ connectionUrl, username, password }));
        dispatch({ type: POST_CONNECTION, payload: response.data });
        history.push('/conexiones');
    }
}

我试图做测试脚本,但是当我运行它时它会抛出一个错误。脚本如下所示:

describe('Pruebas de Conexiones', () => {
    describe('Action Creators', () => {
        it("Crear conexión", async () => {
            const dispatch = jest.fn();
            const {data} = await postConnection('www.google.com', 'root', 'password')(dispatch);
            dispatch({});
        });
    });
});

当我尝试运行测试脚本时,它会抛出下一个错误:

Request failed with status code 401

      at createError (node_modules/axios/lib/core/createError.js:16:15)
      at settle (node_modules/axios/lib/core/settle.js:17:12)
      at IncomingMessage.handleStreamEnd (node_modules/axios/lib/adapters/http.js:237:11)

有没有办法测试像我这样的操作创建者?

编辑 现在我有一个模拟 axios 的模拟文件,看起来像这样:

const mockAxios = jest.genMockFromModule('axios');

mockAxios.create = jest.fn(() => mockAxios)

export default mockAxios

但现在我的问题是我不知道如何在测试文件中实现这一点。现在我有这样的东西:

import thunk from 'redux-thunk';
import mockAxios from 'axios';

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

describe('Test de conexiones', () =>{
    describe('Action Creators', () =>{
        it('Agregar conexión', async () =>{
            const store = mockStore({});
            const mockData = {data:123};
            mockAxios.get.mockImplementationOnce(()=>Promise.resolve({data: mockData}));

            const expectedActions = [
                {type: POST_CONNECTION, data: mockData}
            ]
            const dispatch = jest.fn();
            const response = await postConnection('www.google.com','root','password')(dispatch);
        });
    });
});

它会抛出下一个错误:

TypeError: Cannot read property 'data' of undefined

      12 |     return async (dispatch) => {
      13 |         const response = await requireAuthActions.post('/db/conexion', JSON.stringify({ connectionUrl, username, password }));
    > 14 |         dispatch({ type: POST_CONNECTION, payload: response.data });
         |                                                             ^
      15 |         history.push('/conexiones');
      16 |     }
      17 | }

【问题讨论】:

  • 您遇到的错误是什么?您是否尝试过使用您的jest.fn() 作为测试间谍?通常,您的测试不应调用外部服务,因此您也需要模拟该响应,忘记整个 async/await 方法。
  • @jmargolisvt 我已经用错误日志更新了我的问题。
  • 您没有模拟您的 API,因此它调用了具有不完整数据的真实服务器。更好地模拟它。
  • @jmargolisvt 是这样的吗? expect(dispatch.mock.calls).toEqual(data);

标签: javascript redux jestjs


【解决方案1】:

我看到两种可能的方法:使用真实商店或redux-mock-store

步骤类似:

  1. 开设商店。
  2. 模拟外部 API,例如 http 调用或至少 requireAuthActions 模块并带有一些响应(成功或失败)(检查 jest's docs on mocking
  3. 暂停等待(await Promise.resolve();flush-promisessetTimeout(..., 0))所有异步的东西,比如你在#2 中嘲笑的Promise.resolve()
  4. 如果您使用真正的商店 - 然后检查商店(如果您使用此抽象级别,则使用选择器)是否包含您希望根据您在 #2 中模拟的响应看到的数据
  5. 如果是 redux-mock-store,则您无法验证状态中的数据(因此减速器应单独测试),因此只需验证生成的操作列表 - 是否符合基于在 #2 中模拟的响应的预期。

【讨论】:

  • 如何进行模拟?我尝试创建一个名为 mock 的文件夹并在其中添加一个 axios.js 文件,其中包含此代码 get: jest.fn(() => Promise.resolve({ data: {} })) 但没有运行。
  • 文件夹应该命名为__mocks__,对于mocking modules。我们也可以使用automocking 就像jest.mock('axios'); 一样简单检查两个链接以获取大量示例。
  • 我已经更改了mock,现在是这样const mockAxios = jest.genMockFromModule('axios'); mockAxios.create = jest.fn(() => mockAxios) export default mockAxios,但现在我不知道如何在测试文件中实现这个mock
  • 我已经用新的模拟更新了我的答案,以及我如何尝试在测试文件中实现它。我仍然不知道如何为测试实现模拟。
  • 您是否使用调试器检查过您的模拟是否被正确调用?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2018-12-23
  • 2019-01-19
  • 1970-01-01
  • 2020-03-09
  • 1970-01-01
  • 1970-01-01
  • 2018-09-28
相关资源
最近更新 更多