React/Redux应用中Fetch Action的Jest单元测试疑问
关于Redux异步Action测试返回包含数据的Action数组的问题
嘿,刚接触单元测试和Jest很正常,别担心——你遇到的情况完全不是代码问题,反而可能是你在测试更贴近真实业务的异步Action,而Redux官方文档的示例可能只展示了同步Action的测试场景而已。
我来给你拆解清楚:
1. 同步 vs 异步Action的区别
- 同步Action:就是那种直接返回
{ type: 'XXX', payload: ... }的纯函数,测试的时候直接调用Action Creator就能拿到这个对象,所以官方示例里只返回Action类型(或者带固定payload的对象)。 - 异步Action:如果你的Action是用来从数据库/API获取资源的,大概率用了Redux Thunk这类中间件,它返回的是一个函数,函数内部会分步骤dispatch多个Action——比如请求开始的
FETCH_REQUEST、请求成功的FETCH_SUCCESS(带获取到的数据)、请求失败的FETCH_FAILURE。这时候用redux-mock-store这类工具测试时,store.getActions()会返回所有dispatch过的Action组成的数组,里面自然会包含带真实(或Mock)数据的Success Action。
2. 为什么你的结果和官方示例不一样?
官方文档的示例可能只是为了演示最基础的Action测试逻辑,只关注Action类型是否正确,但实际业务中,我们不仅要验证Action的类型,还要验证payload里的数据是否符合预期(比如是否正确拿到了数据库返回的资源),这才是完整的测试。
3. 验证你的代码是否正确的小技巧
你可以按照这个思路检查:
- 确认你的Action Creator是异步的(比如用了Thunk,返回的是
async (dispatch) => { ... }这样的函数) - 测试时用Mock数据代替真实数据库请求(避免测试依赖外部资源,也更稳定),比如用
jest.mock模拟你的数据库查询函数,让它返回固定的测试数据 - 然后验证
store.getActions()返回的数组里,每个Action的type是否正确,payload是否和你Mock的数据一致
举个简单的实践例子:
你的异步Action代码(示例)
export const fetchResources = () => async (dispatch) => { dispatch({ type: 'FETCH_RESOURCES_START' }); try { // 假设这是你的数据库查询函数 const resources = await db.getResources(); dispatch({ type: 'FETCH_RESOURCES_SUCCESS', payload: resources }); } catch (err) { dispatch({ type: 'FETCH_RESOURCES_ERROR', payload: err.message }); } };
对应的测试代码
import configureMockStore from 'redux-mock-store'; import thunk from 'redux-thunk'; import { fetchResources } from './actions'; import db from './db'; // 配置Mock Store const mockStore = configureMockStore([thunk]); // Mock数据库查询函数,返回测试用的固定数据 jest.mock('./db', () => ({ getResources: jest.fn().mockResolvedValue([{ id: 1, name: 'Test Resource' }]) })); describe('fetchResources Action', () => { it('should dispatch start and success actions with correct data', async () => { // 预期会dispatch的Action数组 const expectedActions = [ { type: 'FETCH_RESOURCES_START' }, { type: 'FETCH_RESOURCES_SUCCESS', payload: [{ id: 1, name: 'Test Resource' }] } ]; const store = mockStore({}); // 执行异步Action await store.dispatch(fetchResources()); // 验证dispatch的Action是否符合预期 expect(store.getActions()).toEqual(expectedActions); // 验证数据库查询函数被正确调用 expect(db.getResources).toHaveBeenCalledTimes(1); }); });
在这个测试里,store.getActions()返回的数组就包含了带数据的Success Action,这完全是正确的——我们需要确保Action不仅类型对,传递的数据也没问题。
总结
你看到的包含真实数据的Action数组是正常现象,说明你的异步Action流程是符合预期的。只要你验证了每个Action的type和payload都正确,代码就没有问题。如果想让测试更可靠,记得用Mock数据代替真实数据库请求哦~
内容的提问来源于stack exchange,提问作者diegoalmesp
相关产品推荐
相关产品推荐

