Sinon间谍与同构取

时间:2017-04-23 00:09:49

标签: reactjs fetch jestjs sinon thunk

我创建了一个简单的thunk操作来从API获取数据。它看起来像这样:

import fetch from 'isomorphic-fetch';

function json(response) {
  return response.json();
}

/**
 * Fetches booksfrom the server
 */
export function getBooks() {
  return function(dispatch) {
    return fetch("http://localhost:1357/book", {mode: "cors"})
    .then(json)
    .then(function(data) {
      dispatch({
        type: "GET_Books",
        books: data
      });
      // This lets us use promises if we want
      return(data);
    });
  }
};

然后,我写了一个这样的测试:

import configureMockStore from 'redux-mock-store';
import thunk from 'redux-thunk';
import {getBooks} from '../../actions/getBooks';
import nock from 'nock';
import fetch from 'isomorphic-fetch';
import sinon from 'sinon';

it('returns the found devices', () => {
  var devices = nock("http://localhost:1357")
                .get("/book")
                .reply(200,
                      {});
  const store = mockStore({devices: []});
  var spy = sinon.spy(fetch);
  return store.dispatch(getBooks()).then(() => {
  }).catch((err) => {
  }).then(() => {
    // https://gist.github.com/jish/e9bcd75e391a2b21206b
    expect(spy.callCount).toEqual(1);
    spy.retore();
  });
});

此测试失败 - 通话计数为0,而不是1。为什么没有sinon嘲笑这个函数,我需要做些什么才能让它模拟这个函数呢?

1 个答案:

答案 0 :(得分:3)

您正在测试文件中导入fetch而不是在任何地方调用它。这就是呼叫计数为零的原因。

这引出了一个问题,即当测试描述为“返回找到的设备”时,为什么要测试动作创建者是否被调用。

thunk动作创建者的主要目的是成为一个动作创建者,它返回一个可以在以后调用的函数。稍后调用的此函数可以接收存储分派和状态作为其参数。这允许返回的函数异步调度其他操作。

在测试thunk action creator时,您应该关注在以下情况下是否调度了正确的操作。

  1. 提出请求

  2. 收到回复并且提取成功

  3. 发生错误,提取失败

  4. 尝试以下内容:

    export function fetchBooksRequest () {
      return {
        type: 'FETCH_BOOKS_REQUEST'
      }
    }
    
    export function fetchBooksSuccess (books) {
      return {
        type: 'FETCH_BOOKS_SUCCESS',
        books: books
      }
    }
    
    export function fetchBooksFailure (err) {
      return {
        type: 'FETCH_BOOKS_FAILURE',
        err
      }
    }
    
    
    /**
     * Fetches books from the server
     */
    export function getBooks() {
      return function(dispatch) {
        dispatch(fetchBooksRequest(data));
    
        return fetch("http://localhost:1357/book", {mode: "cors"})
        .then(json)
        .then(function(data) {
          dispatch(fetchBooksSuccess(data));
          // This lets us use promises if we want
          return(data);
        }).catch(function(err) {
          dispatch(fetchBooksFailure(err));
        })
      }
    };
    

    <强> Tests.js

    import configureMockStore from 'redux-mock-store'
    import thunk from 'redux-thunk'
    import fetchMock from 'fetch-mock'  // You can use any http mocking library
    
    import {getBooks} from '../../actions/getBooks';
    
    const middlewares = [ thunk ]
    const mockStore = configureMockStore(middlewares)
    
    describe('Test thunk action creator', () => {
      it('expected actions should be dispatched on successful request', () => {
        const store = mockStore({})
        const expectedActions = [ 
            'FETCH_BOOKS_REQUEST', 
            'FETCH_BOOKS_SUCCESS'
        ]
    
     // Mock the fetch() global to always return the same value for GET
     // requests to all URLs.
     fetchMock.get('*', { response: 200 })
    
        return store.dispatch(fetchBooks())
          .then(() => {
            const actualActions = store.getActions().map(action => action.type)
            expect(actualActions).toEqual(expectedActions)
         })
    
        fetchMock.restore()
      })
    
      it('expected actions should be dispatched on failed request', () => {
        const store = mockStore({})
        const expectedActions = [ 
            'FETCH_BOOKS_REQUEST', 
            'FETCH_BOOKS_FAILURE'
        ]
     // Mock the fetch() global to always return the same value for GET
     // requests to all URLs.
     fetchMock.get('*', { response: 404 })
    
        return store.dispatch(fetchBooks())
          .then(() => {
            const actualActions = store.getActions().map(action => action.type)
            expect(actualActions).toEqual(expectedActions)
         })
    
        fetchMock.restore()
      })
    })