在进行单元测试时,是否可以在React中对setState方法进行存根或监视?

时间:2017-04-29 23:28:22

标签: unit-testing reactjs sinon enzyme

我的组件中有以下功能:

method(args) {
 fetch(args)
  .then((response) => {
    this.setState({
      element: response
      error: false
    });
  })
  .catch((error) => {
    this.setState({
      error: true
    });
  });
}

我正在尝试为它编写单元测试,所以我使用fetch-mock和自定义响应模拟了fetch调用。我想检查调用此方法时是否更新状态,并且它似乎不起作用。我正在使用酶,期望和sinon,并且在设置component.setState = sinon.spy或将其删除时,未能成功调用间谍。我如何检查是否使用某些元素调用了setState,或者我的单元测试方法是错误的?

4 个答案:

答案 0 :(得分:3)

在实例化组件之前,您似乎需要在原型中监视/存根setState。我有一个类似的问题,只是间谍实例的setState方法不起作用。基于https://medium.com/@tjhubert/react-js-testing-setstates-callback-907df1fe720d,这是sinon的一种方法:

<强> Component.js

...
method {
  this.setState({property:'value'})
}
...

<强> Component.test.js

...
const setState = sinon.stub(Component.prototype, ‘setState’);
const component = shallow(<Component />);
component.instance().method();
expect(setState).to.be.calledOnce;
...

注意:我的用例是使用jasmine,并且避免渲染以测试行为,所以我知道的解决方案看起来像:

Component.prototype.setState = jasmine.createSpy();
const sut = new Component();
sut.method();
expect(sut.setState).toHaveBeenCalledWith({property:'value'});

答案 1 :(得分:0)

假设在组件安装并且方法已被存根时调用该方法,请尝试:

it('should update state with response', () => {
  const wrapper = mount(<Component />);

  return Promise.resolve().then(() => {
    expect(wrapper.state('error')).to.be.false;
  });
});

返回一个promise允许你以比在setTimeout中使用回调更少hacky的方式测试异步行为。

我使用sinon作为存根,所以在测试中我会有这样的东西:

sinon.stub(window, 'fetch').resolves(mockedResponse);

答案 2 :(得分:0)

您可以暂时模拟/替换组件的setState()方法并等待其下一次执行。这样的事情可能会起到作用:

function onNextSetState(component) {
  const instance = component.instance()
  const originalSetState = instance.setState.bind(instance)
  return new Promise(resolve => {
    instance.setState = (state, callback) => {
      originalSetState(state, (...args) => {
        instance.setState = originalSetState
        resolve()
        if (callback) {
          callback(...args)
        }
      }  
    }
  }
}

it('should update state with response', async () => {
  const component = mount(<Component />)
  component.instance().method()   // we assume this runs .setState inside()
  await onNextSetState(component) // we wait for the next re-render

  // we can be sure the state is what we want it to be:
  expect(component.state('error')).toBe(false)
})

请注意,如果您想多次等待,可能更容易/更好地使用Observable而不是Promise。

答案 3 :(得分:0)

我能够使用以下内容存根setState:

let setStateStub = sinon.stub(prototype, 'setState')

完成存根后,您还需要恢复()原始文件。 您可以通过在存根之后添加以下内容来执行此操作:

setStateStub.restore()

:)