如何测试 redux-thunk 中间件异步功能?

Posted

技术标签:

【中文标题】如何测试 redux-thunk 中间件异步功能?【英文标题】:How to test redux-thunk middleware async functions? 【发布时间】:2016-04-24 00:25:27 【问题描述】:

我正在尝试使用 mocha、chai 和 sinon 测试我的 asyn thunk 中间件 功能(我的第一次!)。

请考虑我的文件:

ayncActionCreators.js

export const fetchCurrentUser = () => 
   return (dispatch) => 
      setTimeout(dispatch, 100);
   
;

ayncActionCreators.spec.js

//...
it('Should work', () => 
   const dispatch = sinon.spy();
   const action = fetchCurrentUser();

   action(dispatch);

   expect(dispatch.called).to.be.true;
);

我还没有实现 fetchCurrentUser 函数 - 只是假设它需要一些“服务器”时间,然后它会调用 'dispatch()'。

由于异步流程,规范失败。如果我在期望之前添加 101 毫秒的 setTimeout - 它会通过。

我的代码将使用一些返回承诺的 DB API,因此异步函数最终将如下所示:

//...
return (dispatch) => 
   return dbAPI.fetchUser().then(dispatch(....));

所以我尝试要求 dbAPI 并在测试中创建一个 sinon.stub().returns(Promise.resolve()) 并且它没有正常工作(我认为由于存根返回一个已解决的承诺 - async 函数将像同步函数一样工作)。

我应该如何测试这样的异步函数有什么想法吗?

谢谢, 阿米特。

【问题讨论】:

【参考方案1】:

不要用 sinon 模拟 dispatch,写你自己的,完成后调用 Mocha 的done()

it('Should work', (done) => 
   const dispatch = () => 
     // Do your tests here
     done();
   ;
   const action = fetchCurrentUser();

   action(dispatch)
     // Also allow quick failures if your promise fails
     .catch(done);
)

如果你只是想确保调度被调用,那么 mocha 将超时。对异步操作创建者返回的承诺的捕获允许错误显示在正确的位置,并且测试失败而不是超时。

【讨论】:

【参考方案2】:

嗯,我想我找到了解决办法:

假设我的异步函数如下所示:

//...
return (dispatch) => 
   return dbAPI.fetchUser().then(dispatch(....));

然后我可以编写如下规范:

it('Should work', () => 
   dbAPI.fetchUser = sinon.stub().returns(Promise.resolve(username: 'John'));

   const dispatch = sinon.spy();
   const action = fetchCurrentUser();

   action(dispatch).then(() => 
      expect(dispatch.called).to.be.true;
   );
);

我不知道这是否是一种解决方法,但它确实有效。我将不胜感激您对更好的方法的意见...

谢谢, 阿米特。

【讨论】:

这是在动作创建器中执行异步效果的不幸缺点之一,它们很难测试。如果坚持使用 redux-thunk 是您唯一的选择,那么这似乎是运行测试的最简洁方式。还有许多其他库可以使用 redux 执行异步操作,这有助于提高可测试性,并且如果您能够进行更改,则不需要您模拟您的 API,但是 如果您要做的只是确保调用了调度,那么这将起作用。如果您想测试调用什么调度(这可能更有意义),那么您可以使用 mocha 的 done() 函数并编写自己的调度,正如我在回答中详述的那样。

以上是关于如何测试 redux-thunk 中间件异步功能?的主要内容,如果未能解决你的问题,请参考以下文章

redux的中间件之redux-thunk

redux的中间件之redux-thunk

redux的中间件之redux-thunk

redux-thunk:错误:动作必须是普通对象。使用自定义中间件进行异步操作

使用redux-thunk完成异步connect的第二个参数的对象写法。

如何解决:错误:操作必须是普通对象。使用自定义中间件进行异步操作