【问题标题】:Unit test for Redux action which dispatches data from database用于从数据库分派数据的 Redux 操作的单元测试
【发布时间】:2021-03-03 19:52:25
【问题描述】:

我有一个像下面这样的动作

index.js

export const dataCount = () => {
  return async (dispatch) => {
    getDataCount().then((data) => {
      dispatch({ type: 'FETCH_DATA_COUNT', payload: data});
    });
  };
};

这里的 getDataCount 是一个辅助函数,它返回一个带有从数据库中获取的数据的承诺。

我的测试暂时是这样的。

import configureStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import dataCount from '../index';
import getDataCount from '../helper';
    
const middlewares = [thunk];
const mockStore = configureStore(middlewares);
const store = mockStore();
let dataValue = '';

describe('fetchData', () => {
  beforeEach(() => { // Runs before each test in the suite
    dataValue = jest.fn(getDataCount);
    store.clearActions();
  });

  it('has the correct action and payload for dataCount', async () => {
    dataValue .mockReturnValue({ total : 13 });
    const expectedActions = [
      {
        payload: dataValue(),
        type: 'FETCH_DATA_COUNT'
      }
    ];
    await getDataCount().then((res) => {
        store.dispatch(dataCount());
        expect(store.getActions()).toEqual(expectedActions);
    });
  });
});

测试失败,因为 store.getActions() 返回 [] 并且我知道我在调度时做错了什么。任何建议都会有很大帮助。

【问题讨论】:

    标签: reactjs unit-testing redux jestjs enzyme


    【解决方案1】:

    有几件事我们可以通过这个测试做得更好。

    您的动作创建者应该返回我们在内部使用的承诺。如果我们这样做,我们可以在异步操作完成后将事情链接到调度上。由于它的 async 关键字,您的确实已经返回了一个承诺,但这可能会导致时间问题。

    export const dataCount = () => {
      return async (dispatch) => {
        return getDataCount().then((data) => {
          dispatch({ type: 'FETCH_DATA_COUNT', payload: data });
        });
      };
    };
    

    第二个变化是将我们的断言链接在测试代码的调度后面的测试中。所以我们等待调度完全解决,然后比较动作。

    it('has the correct action and payload for dataCount', async () => {
      const expectedActions = [
        {
          payload: { total: 13 },
          type: 'FETCH_DATA_COUNT'
        }
      ];
      // await the whole promise chain for jest to know how long to wait
      await store.dispatch(dataCount())
        .then(() => { // dispatch is resolved here
          expect(store.getActions()).toEqual(expectedActions)
        })
    });
    

    第三件事,dataValue 模拟没有按照你的想法做。要模拟这个函数,你必须依赖注入它。最简单的情况是将其作为参数提供给dataCount

    store.dispatch(dataCount(dataValue))
    

    依赖注入对您的单元测试有好处,因为现在测试将进入网络或getDataCount 的任何地方,这会使您的测试变慢并且容易出错。

    如果我有任何未解决的问题或错误,请告诉我。

    【讨论】:

    • 我尝试了您的解决方案,但 store.getActions() 仍然只返回 []。所以测试失败了。 getDataCount() 方法返回一个带有数据库数据的承诺。知道如何进行吗?
    • 我在我的电脑上运行它。推到github你可以自己试试比较。也许我的描述不清楚。有趣的文件位于scr/redux 下,您可以使用npm t 运行测试
    • 感谢您的更新。如果 getDataCount 总是返回 { total : 13 },它就可以工作。但是 getDataCount() 是一个从数据库返回数据的函数。所以返回值并不总是 { total: 13 } 。当它从数据库中获取数据时,我们是否需要直接调用 getDataCount ?我想它需要被模拟才能返回一个值。对不起,如果我让你感到困惑。
    • 是的,现在我们的测试依赖于网络。要解决这个问题,您有几个选择。一种是用jest by mocking the module 模拟getDateCount。我更新了我的master branch 给你看。您还可以查看依赖注入。有很多方法可以做到这一点。我在我的injection branch中展示了一个@
    猜你喜欢
    • 1970-01-01
    • 2011-07-10
    • 1970-01-01
    • 1970-01-01
    • 2018-06-18
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2016-02-17
    相关资源
    最近更新 更多