如何正确测试反应组分方法

时间:2017-01-13 00:41:27

标签: reactjs sinon enzyme nock

我已经在React中开发了一段时间用于我的工作,但最近我被要求使用伊斯坦布尔获得一些~100%测试覆盖率的应用程序。在过去的几天里,我已经为这个应用程序单独写了160多个测试,但是我还没能覆盖我代码的某些部分。我在覆盖AJAX调用,setTimeout回调和需要其他组件正常运行的组件方法方面遇到的问题最多。 我读过几个SO问题都无济于事,我相信这是因为我接近这个问题不正确。我正在使用Enzyme,Chai断言,Mocha,伊斯坦布尔报道,sinon为间谍,并且因为我不能让sinon fakeServer工作而正在考虑nock。

以下是有问题的组件方法:

_getCategoriesFromServer() {
const _this = this;
sdk.getJSON(_this.props.sdkPath, {
    itemsperpage: 10000
}).done(function(data) {
    _this.setState({
        isLoaded: true,
        categories: _this.state.categories.concat(data)
    });
});

}

以下是该组件的测试:

 it('should call _getCategoriesFromServer', () => {
    sinon.spy(CategoryTree.prototype, '_getCategoriesFromServer');
    wrapper = mount(<CategoryTree {...props} />);
    expect(CategoryTree.prototype._getCategoriesFromServer.calledOnce).to.be.true;
});

sdk只是一个使用getJSON构造jQuery API调用的模块。 我的测试覆盖了函数调用,但它没有覆盖此处显示的.done回调:enter image description here 所以我的问题是,我怎样才能正确测试.done? 如果有人有文章,教程,视频,任何解释如何正确测试组件方法的东西,我真的很感激!

第二个问题是,我如何测试一个作为prop组件传递给子组件的方法?根据测试覆盖率要求,我必须测试该方法,但其唯一目的是传递给子组件以用作onClick。这很好,但onClick依赖于另一个AJAX调用返回子组件中的数据。 我最初的冲动是只使用酶.find找到onClick并模拟一个click事件,但是那个onClick的元素不存在,因为AJAX调用没有带回测试环境中的数据。 如果您已经读过这篇文章,我向您致敬。如果你能提供帮助,我感谢你!

1 个答案:

答案 0 :(得分:5)

您可以使用重新布线(https://github.com/jhnns/rewire)来测试您的组件,如下所示:

// let's said your component is ListBox.js
var rewire = require("rewire");
var myComponent = rewire("../components/ListBox.js");

const onDone = sinon.spy()
const sdkMock = {
    getJSON (uri, data) {
       return this.call('get', uri, data);
    },
    call: function (method, uri, data) {
       return { done: function(){ onDone() } }
    }
};
myComponent.__set__("sdk", sdkMock);

最后你将测试是否像这样调用done函数:

expect(onDone.calledOnce)to.be.true

这应该按预期工作。如果您需要更多选项,您可以在GitHub中看到重新连接的所有选项。

<强> BABEL

如果您使用babel作为转换器,则需要使用babel-plugin-rewire(https://github.com/speedskater/babel-plugin-rewire),您可以像这样使用它:

sdk.js

function call(method, uri, data) {
   return fetch(method, uri, data);
}
export function getJSON(uri, data) {
   return this.call('get', uri, data);
}

yourTest.js

import { getJSON, __RewireAPI__ as sdkMockAPI } from 'sdk.js';

describe('api call mocking', function() {
   it('should use the mocked api function', function(done) {
      const onDone = sinon.spy()
      sdkMockAPI.__Rewire__('call', function() {
         return { done: function(){ onDone() } }
      });
      getJSON('../dummy.json',{ data: 'dummy data'}).done()
      expect(onDone.calledOnce)to.be.true
      sdkMockAPI.__ResetDependency__('call')
   })
})