Sinon间谍与同构取

问题描述 投票:2回答:1

我创建了一个简单的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 fetch jestjs sinon thunk
1个回答
3
投票

您正在测试文件中导入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()
  })
})
© www.soinside.com 2019 - 2024. All rights reserved.