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

如何为含循环与Axios请求的React异步方法编写单元测试用例?

没问题,我来帮你搞定这个带循环的Redux thunk函数的单元测试!首先,我们得拆解这个函数的逻辑:它接收包含collections的参数,循环每个集合,每次dispatch两个action——其中getBook是异步的(你提到用到了Axios GET),还有一个同步的ADD action。下面一步步来写测试用例:

测试带循环的Redux Thunk异步函数

首先我们需要准备必要的测试工具,然后分场景编写测试用例。

1. 安装依赖

先安装测试所需的工具包:

npm install --save-dev jest redux-mock-store redux-thunk
# 或者用yarn
yarn add --dev jest redux-mock-store redux-thunk

2. 模拟异步依赖

因为getBook内部调用了Axios,我们不需要真的发网络请求,用Jest模拟这个异步action:

// 假设getBook在你的项目路径是 ./actions/bookActions
import { getBook } from './actions/bookActions';

// 模拟getBook返回一个resolved的Promise
jest.mock('./actions/bookActions', () => ({
  getBook: jest.fn(() => Promise.resolve())
}));

3. 配置模拟Redux Store

用redux-mock-store创建带thunk中间件的模拟store,方便追踪dispatch的action:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';

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

4. 编写测试用例

我们分三个核心场景来测试:空集合、单个集合、多个集合。

场景1:空集合时不执行任何dispatch

describe('someMethod', () => {
  it('should not dispatch any actions when collections is empty', async () => {
    const store = mockStore({});
    const args = { collections: [] };

    // 调用thunk函数并等待完成
    await store.dispatch(someMethod(args));

    // 验证没有任何action被dispatch
    const actions = store.getActions();
    expect(actions).toEqual([]);
  });
});

场景2:单个集合时验证action正确dispatch

注意:我修正了你原代码里的笔误(boolURL应该是bookUrl),且假设collection包含libraryId字段(原代码里没解构,应该是漏了)。

it('should dispatch getBook and ADD action for a single collection', async () => {
  const testCollection = {
    libraryUrl: 'https://example.com/library',
    bookUrl: 'https://example.com/book',
    libraryId: 'lib-123'
  };
  const store = mockStore({});
  const args = { collections: [testCollection] };

  await store.dispatch(someMethod(args));

  const actions = store.getActions();
  
  // 验证getBook被调用的参数正确
  expect(getBook).toHaveBeenCalledWith({
    bookUrl: testCollection.bookUrl,
    libraryURL: testCollection.libraryUrl,
    libraryId: testCollection.libraryId
  });
  
  // 验证ADD action的payload正确
  expect(actions).toContainEqual({
    type: ASSESSMENT.BOOK.ADD,
    payload: {
      bookUrl: testCollection.bookUrl,
      libraryId: testCollection.libraryId
    }
  });
  
  // 总共应该dispatch了2个action
  expect(actions.length).toBe(2);
});

场景3:多个集合时验证每个元素对应的action都被触发

it('should dispatch actions for every collection in the list', async () => {
  const testCollections = [
    {
      libraryUrl: 'https://example.com/lib1',
      bookUrl: 'https://example.com/book1',
      libraryId: 'lib-001'
    },
    {
      libraryUrl: 'https://example.com/lib2',
      bookUrl: 'https://example.com/book2',
      libraryId: 'lib-002'
    }
  ];
  const store = mockStore({});
  const args = { collections: testCollections };

  await store.dispatch(someMethod(args));

  // 验证getBook被调用了2次,参数分别对应两个集合
  expect(getBook).toHaveBeenCalledTimes(2);
  expect(getBook).toHaveBeenNthCalledWith(1, {
    bookUrl: testCollections[0].bookUrl,
    libraryURL: testCollections[0].libraryUrl,
    libraryId: testCollections[0].libraryId
  });
  expect(getBook).toHaveBeenNthCalledWith(2, {
    bookUrl: testCollections[1].bookUrl,
    libraryURL: testCollections[1].libraryUrl,
    libraryId: testCollections[1].libraryId
  });

  // 筛选出所有ADD action,验证数量和内容
  const addActions = actions.filter(action => action.type === ASSESSMENT.BOOK.ADD);
  expect(addActions.length).toBe(2);
  expect(addActions[0].payload).toEqual({
    bookUrl: testCollections[0].bookUrl,
    libraryId: testCollections[0].libraryId
  });
  expect(addActions[1].payload).toEqual({
    bookUrl: testCollections[1].bookUrl,
    libraryId: testCollections[1].libraryId
  });

  // 总共有4个action(2个getBook + 2个ADD)
  expect(actions.length).toBe(4);
});

额外提示

  • 如果getBook可能抛出错误,你可以加一个测试场景,验证错误时的行为(比如dispatch错误action)
  • 原代码里的Math.random().toString()生成的containerId没被用到,如果你后续要用它,记得在测试里处理随机值(比如用Jest mock Math.random)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.14 08:01:04