如何为含循环与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 mockMath.random)
内容的提问来源于stack exchange,提问作者shiva maratha
相关产品推荐
相关产品推荐

