Javascript 测试调用API的redux操作
测试此功能的最佳方法是什么Javascript 测试调用API的redux操作,javascript,unit-testing,redux,redux-thunk,Javascript,Unit Testing,Redux,Redux Thunk,测试此功能的最佳方法是什么 export function receivingItems() { return (dispatch, getState) => { axios.get('/api/items') .then(function(response) { dispatch(receivedItems(response.data)); }); }; } 这就是我目前拥有的 describe('Items Action Cre
export function receivingItems() {
return (dispatch, getState) => {
axios.get('/api/items')
.then(function(response) {
dispatch(receivedItems(response.data));
});
};
}
这就是我目前拥有的
describe('Items Action Creator', () => {
it('should create a receiving items function', () => {
expect(receivingItems()).to.be.a.function;
});
});
我将使用存根
axios
(例如使用),编写一个测试,实际调用receivingItems()(dispatch,getState)
,并确保使用正确的数据调用dispatch
来自Redux配方:
对于使用或其他中间件的异步操作创建者,最好完全模拟Redux存储进行测试。您仍然可以对模拟存储使用applyMiddleware()
,如下所示(您可以在中找到以下代码)。您还可以使用来模拟HTTP请求
function fetchTodosRequest() {
return {
type: FETCH_TODOS_REQUEST
}
}
function fetchTodosSuccess(body) {
return {
type: FETCH_TODOS_SUCCESS,
body
}
}
function fetchTodosFailure(ex) {
return {
type: FETCH_TODOS_FAILURE,
ex
}
}
export function fetchTodos() {
return dispatch => {
dispatch(fetchTodosRequest())
return fetch('http://example.com/todos')
.then(res => res.json())
.then(json => dispatch(fetchTodosSuccess(json.body)))
.catch(ex => dispatch(fetchTodosFailure(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, done) {
if (!Array.isArray(expectedActions)) {
throw new Error('expectedActions should be an array of expected actions.')
}
if (typeof done !== 'undefined' && typeof done !== 'function') {
throw new Error('done should either be undefined or function.')
}
function mockStoreWithoutMiddleware() {
return {
getState() {
return typeof getState === 'function' ?
getState() :
getState
},
dispatch(action) {
const expectedAction = expectedActions.shift()
try {
expect(action).toEqual(expectedAction)
if (done && !expectedActions.length) {
done()
}
return action
} catch (e) {
done(e)
}
}
}
}
const mockStoreWithMiddleware = applyMiddleware(
...middlewares
)(mockStoreWithoutMiddleware)
return mockStoreWithMiddleware()
}
describe('async actions', () => {
afterEach(() => {
nock.cleanAll()
})
it('creates FETCH_TODOS_SUCCESS when fetching todos has been done', (done) => {
nock('http://example.com/')
.get('/todos')
.reply(200, { todos: ['do something'] })
const expectedActions = [
{ type: types.FETCH_TODOS_REQUEST },
{ type: types.FETCH_TODOS_SUCCESS, body: { todos: ['do something'] } }
]
const store = mockStore({ todos: [] }, expectedActions, done)
store.dispatch(actions.fetchTodos())
})
})
我用另一种方式解决了这个问题:注入axios作为动作的依赖项。与“重新布线”依赖项相比,我更喜欢这种方法 因此,我使用相同的方法测试redux连接的组件。当我导出操作时,我导出两个版本:一个带有(用于组件)绑定依赖项,另一个没有(用于测试)绑定依赖项 下面是我的actions.js文件的外观:
import axios from 'axios'
export const loadDataRequest = () => {
return {
type: 'LOAD_DATA_REQUEST'
}
}
export const loadDataError = () => {
return {
type: 'LOAD_DATA_ERROR'
}
}
export const loadDataSuccess = (data) =>{
return {
type: 'LOAD_DATA_SUCCESS',
data
}
}
export const loadData = (axios) => {
return dispatch => {
dispatch(loadDataRequest())
axios
.get('http://httpbin.org/ip')
.then(({data})=> dispatch(loadDataSuccess(data)))
.catch(()=> dispatch(loadDataError()))
}
}
export default {
loadData: loadData.bind(null, axios)
}
然后使用(actions.test.js)进行测试:
在组件内使用操作时,我会导入所有内容:
从“/Actions”导入操作
并发送:
Actions.loadData()//这是绑定了axios的版本。
请记住,createMockStore
已作为一个包发布:您可以使用Hi同步测试异步操作,如果测试的操作是getTodos
,返回的数据是一个巨大的TODO列表,该怎么办?你如何嘲笑这种情景?
import { loadData } from './actions'
describe('testing loadData', ()=>{
test('loadData with success', (done)=>{
const get = jest.fn()
const data = {
mydata: { test: 1 }
}
get.mockReturnValue(Promise.resolve({data}))
let callNumber = 0
const dispatch = jest.fn(params =>{
if (callNumber===0){
expect(params).toEqual({ type: 'LOAD_DATA_REQUEST' })
}
if (callNumber===1){
expect(params).toEqual({
type: 'LOAD_DATA_SUCCESS',
data: data
})
done()
}
callNumber++
})
const axiosMock = {
get
}
loadData(axiosMock)(dispatch)
})
})