Redux - 如何使用 Nock 测试异步 Action

4

我按照redux.org的基本示例测试异步操作

action.js

我的代码是这样的:

import axios from 'axios'

export function getGoodDataStart(){
    return{
        type: "GOOD_DATA_START"
    }
}
export function getGoodDataSuccess(payload){
    console.log('success', payload)
    return {
        type: "GOOD_DATA_SUCCESS",
        payload: payload
    }
}
export function getGoodDataFail(){
    return{
        type: "GOOD_DATA_FAIL"
    }
}
export function getGoodData(){
    return (dispatch) => {
        dispatch( getGoodDataStart() )
        return  axios.get('http://www.google.com/list')
            .then( response => {
                console.log('fake res',response)
                dispatch(getGoodDataSuccess (response) )
            })
            .catch( err => {
                console.log('fake err',err)
            })
    }   
}

test.js

import nock from 'nock'
import React from 'react'
import {expect} from 'chai'
import {getGoodData} from 'registerAction'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'

const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)

describe('Register component', () => {

    it('async action', function () {

        nock('http://www.google.com')
        .get('/list')
        .reply(200,'ok!' )

        const store = mockStore({ 
            myData: '' ,
        })
        const expected = [
            {type: "GOOD_DATA_START"},
            {type: "GOOD_DATA_SUCCESS", payload: 'ok!'}
        ]

        return store.dispatch(getGoodData())
            .then( () => { 
                expect(store.getActions()).to.equal(expected)
            })
    })
})

我遇到的问题是,nock没有阻止请求,它允许函数getGoodData向google.com发出真实请求。我做错了什么?
错误的截图:

enter image description here

这是演示: https://github.com/craigcosmo/react-redux-test 安装: npm i
测试: npm run test
打开网址: http://localhost:5051/webpack-dev-server/

我认为这可能是因为你在 nock 设置中有一个尾随的 /。请改为使用 nock('http://example.com') 而不是 nock('http://example.com/') :) - Mario Tacke
你确定你正在访问完全相同的端点吗? - Mario Tacke
我尝试过那个,但它没有起作用,所以我选择了webpack-dev-server。 - angry kiwi
@BenSidelinger 是的,我愿意。 - angry kiwi
@angry_kiwi,我发布了一个答案,将向您展示如何既不必处理nock,又通过模拟axios并断言正确调用它来删除测试中的axios。 - Ben Sidelinger
显示剩余9条评论
3个回答

3
通常在测试这样的操作时,您需要从方程式中剔除任何不属于您操作的内容。在这种情况下,仅使用nock是无法将axios从方程式中移除的,反而会增加不必要的复杂性。通过使用间谍模拟axios,您避免了进行网络调用,并且根本没有调用axios。这使您只需断言axios以正确的参数进行调用即可。间谍可以返回一个承诺,以便测试所有承诺处理和随后的操作调用。为了证明这一点,我需要添加一个提供间谍的库,因此我选择添加“expect”作为断言和间谍,但如果您想坚持使用chai,那么您也可以轻松做到同样的事情。
以下是一个示例,您根本不需要nock,而只需使用间谍模拟axios:
import React from 'react'
import * as registerAction from 'registerAction'
import configureMockStore from 'redux-mock-store'
import thunk from 'redux-thunk'
import expect from 'expect'

const middlewares = [ thunk ]
const mockStore = configureMockStore(middlewares)

// set up to mock axios methods
import axios from 'axios'
const _get = axios.get

const fakePayload = { foo: 'bar' };
describe('Register component', () => {
    beforeEach(() => {
        // replace the .get method temporarily with a spy
        axios.get = expect.createSpy().andReturn(Promise.resolve(fakePayload));
    })

    afterEach(() => {
        // restore the get method with our saved const
        axios.get = _get;
    })

    it('async action', function () {
        const store = mockStore({
            myData: '' ,
        })
        const expected = [
            {type: "GOOD_DATA_START"},
            {type: "GOOD_DATA_SUCCESS", payload: fakePayload}
        ]

        return store.dispatch(registerAction.getGoodData())
            .then( () => {
                expect(store.getActions()).toEqual(expected)
                expect(axios.get).toHaveBeenCalled()
                expect(axios.get).toHaveBeenCalledWith('http://www.google.com/list')
            })
    })
})

2

阅读https://github.com/node-nock/nock/issues/150

你的测试在控制台上表现得很好-

将这两个脚本添加到你的package.json中运行

    "itest": "mocha --compilers js:babel-register -R spec  \"test/*.test.js\"",
    "itest:watch": "npm run itest -- --watch"

我添加了这两个命令。当运行 'itest' 时,出现错误。错误信息:找不到模块 './options'。 - angry kiwi
你是如何在控制台中运行测试的? - angry kiwi

1
你可能需要类似这样的东西。
beforeEach(() => {
    nock.disableNetConnect();
});

afterEach(() => {
    nock.cleanAll();
    nock.enableNetConnect();
});

启用/禁用真实的HTTP请求


这个解决方案存在同样的问题,操作仍然会发出真实请求。 - angry kiwi
@angry_kiwi 你是在运行应用程序而不是测试,并期望nock拦截它吗?Nock只能在测试中使用。 - yjcxy12
我正在运行测试。 - angry kiwi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接