我正在创建一个用于使用异步操作发出Ajax请求的中间件。中间件截取原始动作,执行ajax请求,并dispatch恢复原始动作以及来自的响应url。
dispatch
url
所以,我的组件只会是这样dispatch的动作
onClick() { dispatch(ActionCreator.fetchUser()); }
其余部分将通过中间件如图所示照顾这里。
我的问题是,单元测试应该怎么做?我应该嘲笑onClick自己吗?还是应该编写一个模拟的中间件并通过模拟的响应转发操作?
onClick
我不确定应该采用哪种方法。我尝试了几种方法,但是我尝试的所有方法都不有意义。
有指针吗?
这里描述了一种更简单的更新方法。 不过,您仍然可以用其他方式进行操作。
现在,我们在官方文档中提供了有关测试异步操作创建者的部分。
对于使用Redux Thunk或其他中间件的异步动作创建者,最好完全模拟Redux存储以进行测试。您仍然可以使用applyMiddleware()模拟存储,如下所示。您还可以使用nock模拟HTTP请求。
applyMiddleware()
function fetchTodosRequest() { return { type: ADD_TODOS_REQUEST }; } function fetchTodosSuccess(body) { return { type: ADD_TODOS_SUCCESS, body }; } function fetchTodosFailure(ex) { return { type: ADD_TODOS_FAILURE, ex }; } export function fetchTodos(data) { return dispatch => { dispatch(fetchTodosRequest()); return fetch('http://example.com/todos') .then(res => res.json()) .then(json => dispatch(addTodosSuccess(json.body))) .catch(ex => dispatch(addTodosFailure(ex))); }; }
可以像这样进行测试:
import expect from 'expect'; import { applyMiddleware } from 'redux'; import thunk from 'redux-thunk'; import * as actions from '../../actions/counter'; import * as types from '../../constants/ActionTypes'; import nock from 'nock'; const middlewares = [thunk]; /** * Creates a mock of Redux store with middleware. */ function mockStore(getState, expectedActions, onLastAction) { if (!Array.isArray(expectedActions)) { throw new Error('expectedActions should be an array of expected actions.'); } if (typeof onLastAction !== 'undefined' && typeof onLastAction !== 'function') { throw new Error('onLastAction should either be undefined or function.'); } function mockStoreWithoutMiddleware() { return { getState() { return typeof getState === 'function' ? getState() : getState; }, dispatch(action) { const expectedAction = expectedActions.shift(); expect(action).toEqual(expectedAction); if (onLastAction && !expectedActions.length) { onLastAction(); } return action; } } } const mockStoreWithMiddleware = applyMiddleware( ...middlewares )(mockStoreWithoutMiddleware); return mockStoreWithMiddleware(); } describe('async actions', () => { afterEach(() => { nock.cleanAll(); }); it('creates FETCH_TODO_SUCCESS when fetching todos has been done', (done) => { nock('http://example.com/') .get('/todos') .reply(200, { todos: ['do something'] }); const expectedActions = [ { type: types.FETCH_TODO_REQUEST }, { type: types.FETCH_TODO_SUCCESS, body: { todos: ['do something'] } } ] const store = mockStore({ todos: [] }, expectedActions, done); store.dispatch(actions.fetchTodos()); }); });