如何在Jest中测试基于Axios的Redux异步Action?
问题修复方案
核心问题分析
- 异步Action未返回Promise:
someFn没有返回axios.get的Promise链,导致store.dispatch(someFn(...))返回undefined,无法调用.then()方法,直接触发TypeError。 - 测试用例错误:
expectedActions格式错误,应该是两个独立的action对象(先LOGIN,再LOGIN_SUCCESS/LOGIN_FAILURE),而非合并成一个对象。- 测试中使用未定义的
response变量,应该用store.getActions()获取已派发的action列表。
- Reducer逻辑错误:
LOGIN_SUCCESS/LOGIN_FAILURE分支的状态更新写法错误,会生成无效的state结构。
修复后的代码
1. 修正异步Action(someFn)
必须返回Promise链,让dispatch能拿到thenable对象:
const someFn = (email, password) => (dispatch) => { dispatch(login(email, password)); // 关键:return axios的Promise链 return axios.get("some API") .then(response => dispatch(loginSuccess())) .catch(error => dispatch(loginFailure())); };
2. 修正Reducer逻辑
调整状态更新方式,生成合理的state结构:
const reducers = (state = { isLoading: false, isLoggedIn: false, error: null }, action) => { switch(action.type) { case LOGIN: return {...state, isLoading: true, user: action.user}; case LOGIN_SUCCESS: return {...state, isLoading: false, isLoggedIn: true}; case LOGIN_FAILURE: return {...state, isLoading: false, isLoggedIn: false, error: action.error || true}; default: return state; } };
3. 修正测试用例
调整expectedActions格式,使用store.getActions()获取派发的actions:
const middleware = [thunk]; const mockStore = configureStore(middleware); const mock = new MockAdapter(axios); it('TEST CASE 5 - 登录成功场景', () => { mock.onGet("...someapi").reply(200, { /* mock payload */ }); const expectedActions = [ // 第一个派发的LOGIN action { type: 'LOGIN', user: { email: 'test@test', password: 123 } }, // 第二个派发的LOGIN_SUCCESS action { type: 'LOGIN_SUCCESS' } ]; const store = mockStore({}); // 返回dispatch的Promise,确保测试等待异步完成 return store.dispatch(someFn("test@test", 123)).then(() => { // 用store.getActions()获取所有已派发的action expect(store.getActions()).toEqual(expectedActions); }); }); // 新增登录失败测试用例 it('TEST CASE 6 - 登录失败场景', () => { mock.onGet("...someapi").reply(500); const expectedActions = [ { type: 'LOGIN', user: { email: 'test@test', password: 123 } }, { type: 'LOGIN_FAILURE' } ]; const store = mockStore({}); return store.dispatch(someFn("test@test", 123)).then(() => { expect(store.getActions()).toEqual(expectedActions); }); });
额外说明
- 测试时每个用例应该单独初始化
store,避免不同测试间的状态污染。 - 你的预期输出存在误解:Redux中每次dispatch是独立的action,最终的state是reducer根据这些action依次更新后的结果,而非把多个action合并成一个对象。
内容的提问来源于stack exchange,提问作者Moez Ben Rebah
相关产品推荐
相关产品推荐

