You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Jest测试分发两个函数的Redux Action?

解决Redux Thunk Action的Jest测试问题

我来帮你搞定这个测试难题,你遇到的doSomething返回undefined、dispatch.mock.calls显示匿名函数的问题,根源在于mock的位置不正确和异步逻辑未正确等待,下面一步步修复:

1. 调整Jest Mock的位置

jest.mock会被Jest自动提升到所有import语句之前执行,如果你把它放在describe内部,会导致import的原模块没有被正确mock,这就是doSomething返回undefined的核心原因。

把jest.mock移到模块顶部,和import同级:

import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';
import functionToTest from 'redux/function-to-test';

// 放在模块顶部,确保mock在import前生效
jest.mock('redux/do-something');
jest.mock('redux/do-something-else');

describe("functionToTest", ()=>{
  // 测试代码放在这里
})

2. Mock Action Creator的返回值

Jest默认会把mock的模块替换成返回undefined的空函数,所以我们需要手动给doSomething和doSomethingElse设置返回值,这样才能追踪它们的调用和dispatch的参数。

根据你的action类型(普通action或thunk),设置对应的mock返回值:

  • 如果是普通action creator(返回action对象):
    doSomething.mockReturnValue({ type: 'DO_SOMETHING' });
    doSomethingElse.mockReturnValue({ type: 'DO_SOMETHING_ELSE' });
    
  • 如果是thunk action creator(返回函数):
    // mock成返回一个可await的promise,确保异步流程能走完
    doSomething.mockReturnValue(() => Promise.resolve());
    doSomethingElse.mockReturnValue(() => Promise.resolve());
    

3. 正确等待异步逻辑

你的functionToTest返回的是一个async函数,测试时如果不await它的执行,测试会在异步操作完成前就结束,导致dispatch.mock.calls只捕获到中间的匿名函数(thunk函数),而不是最终的action。

在测试里添加await,等待整个异步流程完成:

完整修正后的测试代码

import doSomething from 'redux/do-something';
import doSomethingElse from 'redux/do-something-else';
import functionToTest from 'redux/function-to-test';

jest.mock('redux/do-something');
jest.mock('redux/do-something-else');

describe("functionToTest", ()=>{
  const dispatch = jest.fn();

  // 每次测试前重置mock,避免测试间的状态污染
  beforeEach(() => {
    dispatch.mockClear();
    doSomething.mockClear();
    doSomethingElse.mockClear();
    
    // 根据你的实际action类型选择下面的mock方式
    // 普通action creator的mock:
    doSomething.mockReturnValue({ type: 'DO_SOMETHING' });
    doSomethingElse.mockReturnValue({ type: 'DO_SOMETHING_ELSE' });

    // 如果是thunk action creator,替换成这个:
    // doSomething.mockReturnValue(() => Promise.resolve());
    // doSomethingElse.mockReturnValue(() => Promise.resolve());
  });

  test('dispatches doSomething followed by doSomethingElse', async ()=>{
    // 等待异步action执行完成
    await functionToTest()(dispatch);

    // 验证action creators被调用
    expect(doSomething).toHaveBeenCalledTimes(1);
    expect(doSomethingElse).toHaveBeenCalledTimes(1);

    // 验证dispatch的调用顺序和参数
    expect(dispatch).toHaveBeenCalledTimes(2);
    expect(dispatch).toHaveBeenNthCalledWith(1, { type: 'DO_SOMETHING' });
    expect(dispatch).toHaveBeenNthCalledWith(2, { type: 'DO_SOMETHING_ELSE' });
  })
})

关键问题解释

  • doSomething返回undefined:因为之前jest.mock放在describe内部,导致import的是原模块而非mock版本,加上Jest默认mock返回undefined,所以需要调整mock位置并手动设置返回值。
  • dispatch.mock.calls显示匿名函数:因为没有await异步action的执行,测试提前结束,此时dispatch只接收到了thunk函数(而非最终的action对象),通过await确保整个异步流程完成后再验证。

内容的提问来源于stack exchange,提问作者Evanss

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.13 07:35:50