【问题标题】:Sinon spy with isomorphic-fetchSinon spy 同构获取
【发布时间】:2017-09-19 19:57:03
【问题描述】:

我创建了一个简单的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 不模拟该函数,我需要做什么才能使其模拟该函数?

【问题讨论】:

    标签: reactjs jestjs fetch sinon redux-thunk


    【解决方案1】:

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

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

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

    当您测试 thunk 动作创建者时,您应该关注在以下情况下是否调度了正确的动作。

    1. 发出请求

    2. 收到响应,获取成功

    3. 发生错误,提取失败

    尝试以下方法:

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-08
      • 2015-11-26
      • 2019-09-11
      • 1970-01-01
      • 2016-11-04
      • 2020-10-21
      • 2017-05-06
      相关资源
      最近更新 更多