javascript - 如何对异步 Redux 操作进行单元测试以模拟 ajax 响应

标签 javascript reactjs jasmine redux

我正在创建一个中间件,用于使用异步操作发出 ajax 请求。中间件拦截原始操作,执行 ajax 请求,并重新调度原始操作以及来自 url 的响应。

所以,我的组件只会发送这样的 Action

onClick() {
    dispatch(ActionCreator.fetchUser());
}

其余部分将由中间件处理,如图所示here .

我的问题是,单元测试应该怎么做?我应该模拟 onClick 本身吗?或者我应该编写一个模拟中间件并使用模拟响应转发操作?

我不确定应该采用哪种方法。我试过 several stuff ,但我尝试的一切对我来说都没有意义。

有什么建议吗?

最佳答案

注意:下面的回答有点过时了。

描述了一种更简单的更新方法 here .
不过,您仍然可以采用其他方式。


我们现在有 a section on testing async action creators在官方文档中。

对于使用 Redux Thunk 的异步操作创建者或者其他中间件,最好完全模拟 Redux store 进行测试。您仍然可以将 applyMiddleware() 与模拟商店一起使用,如下所示。您也可以使用 nock模拟 HTTP 请求。

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());
  });
});

关于javascript - 如何对异步 Redux 操作进行单元测试以模拟 ajax 响应,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33011729/

相关文章:

javascript - 使用 OOP 方法重新启动 Canvas 动画

javascript - 如何在 ReactJS 中访问选中的元素?

javascript - 如何在express服务器中添加动态路由?

javascript - Angular/karma 类型错误 : Cannot Read Property 'offsetTop' of Undefined

javascript - 语言切换器 - 如何记住用户的选择?

javascript - 移动导航菜单无法正常工作

Javascript 数组比较问题

reactjs - react : Persisting state in tabs

javascript - Angular 2 fakeAsync 在使用 tick() 的函数中等待超时?

angular - 如何在 Angular/Jasmine 测试中模拟 Injector 实例?