【问题标题】:Testing custom redux middleware测试自定义 redux 中间件
【发布时间】:2017-05-05 16:38:36
【问题描述】:

如何对自定义 redux 中间件进行单元测试?我有这个简单的函数,它应该在给定的超时后调度动作但是......我不知道如何处理它。关于这个问题,我没有找到足够的资源。

const callAPiTimeoutMiddleware = store => next => (action) => {
  if (action[CALL_API]) {
    if (action[CALL_API].onTimeout) {
      setTimeout(() => {
        store.dispatch({ type: action[CALL_API].onTimeout });
      }, DEFAULT_TIMEOUT_LENGTH);
    }
  }

  return next(action);
}

这些是我基于已接受答案中提到的博客文章的测试:

describe('callAPiTimeoutMiddleware', () => {
  describe('With [CALL_API] symbol', () => {
    it('should dispatch custom action', () => {
      const clock = sinon.useFakeTimers();
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = {
        [CALL_API]: {
          endpoint: 'endPoint',
          method: 'METHOD',
          types: ['REQUEST_TYPE', 'SUCCESS_TYPE', 'FAILURE_TYPE'],
          onTimeout: 'TIMEOUT_TYPE',
        },
      };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);
      clock.tick(99000);

      expect(fakeStore.dispatch.calledOnce).toEqual(true);
    });


    it('should call next action', () => {
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = {
        [CALL_API]: {
          endpoint: 'endPoint',
          method: 'METHOD',
          types: ['REQUEST_TYPE', 'SUCCESS_TYPE', 'FAILURE_TYPE'],
          onTimeout: 'TIMEOUT_TYPE',
        },
      };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);

      expect(fakeNext.calledOnce).toEqual(true);
    });
  });

  describe('Without [CALL_API] symbol', () => {
    it('should NOT dispatch anything', () => {
      const clock = sinon.useFakeTimers();
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = { type: 'SOME_TYPE' };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);
      clock.tick(99000);

      expect(fakeStore.dispatch.calledOnce).toEqual(false);
    });


    it('should call next action', () => {
      const fakeStore = { dispatch: sinon.spy() };
      const fakeNext = sinon.spy();
      const fakeAction = { type: 'SOME_TYPE' };

      callAPiTimeoutMiddleware(fakeStore)(fakeNext)(fakeAction);

      expect(fakeNext.calledOnce).toEqual(true);
    });
  });
});

【问题讨论】:

  • 它是一个函数 - 像 Mocha、AVA、Jasmine 等通常的单元测试午餐器和像 Sinon 这样的模拟构建器或商店的手动模拟呢?
  • 我真的不知道如何使用这些。 :(你能告诉我工作的例子吗?

标签: unit-testing reactjs asynchronous redux redux-thunk


【解决方案1】:

redux-thunk 中间件已编写单元测试。可以参考here

他只使用摩卡和柴。

here 他在谈论如何为你的 redux 应用编写单元测试。

很好的 blog 关于 redux 中间件以及如何为它们编写单元测试。

【讨论】:

    【解决方案2】:

    我需要更多细节来实际为中间件创建测试,所以这是我针对中间件测试的具体答案:

    中间件可以很容易地进行测试,而无需进行大量模拟。链式箭头函数看起来很吓人,但这只是它们如何被调用的问题。我用 jest 来帮助我进行测试,但您可以用其他东西替换所有 jest 函数。我将直接进入代码并在 cmets 中进行解释:

    import logger from './logger'; //this is your middleware
    const next = jest.fn(); // middleware needs those as parameters, usually calling next(action) at the end to proceed
    const store = jest.fn(); 
    
    const action = { type: 'YOUR_ACTION_TYPE', payload: { your: 'data' }}
    logger(store)(next)(action);
    

    这是您在测试中调用中间件的方式。在您的情况下,如果您想检查是否已调用调度,您可以执行以下操作:

    // Add this in the beginning
    store.dispatch = jest.fn();
    
    // Add this after calling logger()
    expect(store.dispatch.mock.calls).toEqual('whatever calls you expected');
    

    【讨论】:

    • 感谢您的贡献。
    • 有没有更直接的方法来测试它而不是模拟中间件返回的每个函数?
    猜你喜欢
    • 1970-01-01
    • 2020-09-21
    • 2020-01-06
    • 2016-02-29
    • 2020-03-16
    • 2021-03-11
    • 1970-01-01
    • 2015-12-24
    • 1970-01-01
    相关资源
    最近更新 更多