React:如何测试组件更新Props时方法是否被调用?
如何测试React组件更新Props时方法是否被调用?
我来帮你解决这个测试问题!你遇到的错误是因为Jest的toBeCalled()断言只兼容自身的mock函数,不识别Sinon的spy对象,所以才会抛出那个错误。下面给你两种可行的解决方案:
方案一:改用Jest原生Mock函数(推荐)
Jest自带强大的mock功能,完全可以替代Sinon实现方法调用的断言,不需要额外依赖第三方库。具体代码如下:
import React from 'react'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import 'jest-styled-components'; import VideoPlayer from './../src/app/components/VideoPlayer/VideoPlayer'; Enzyme.configure({ adapter: new Adapter() }); test('Checks if togglePlayPause gets called when isPaused prop updates', () => { // 用Jest spyOn监听组件原型上的togglePlayPause方法 const toggleSpy = jest.spyOn(VideoPlayer.prototype, 'togglePlayPause'); // 挂载初始props的组件 const component = mount( <VideoPlayer videoURL="http://localhost:3001/vid/local-video.mp4" volume={100} isPaused={false} /> ); // 更新isPaused props,触发生命周期方法 component.setProps({ isPaused: true }); // 断言方法被调用,还可以指定调用参数 expect(toggleSpy).toHaveBeenCalled(); expect(toggleSpy).toHaveBeenCalledWith(true); // 清理mock,避免影响其他测试用例 toggleSpy.mockRestore(); });
方案二:继续使用Sinon,但改用Sinon的断言方法
如果你坚持使用Sinon,只需要把Jest的断言换成Sinon自己的断言函数即可,不要混用两者的断言体系:
import React from 'react'; import Enzyme, { mount } from 'enzyme'; import Adapter from 'enzyme-adapter-react-16'; import 'jest-styled-components'; import sinon from 'sinon'; import VideoPlayer from './../src/app/components/VideoPlayer/VideoPlayer'; Enzyme.configure({ adapter: new Adapter() }); test('Checks if togglePlayPause gets called with Sinon', () => { const toggleSpy = sinon.spy(VideoPlayer.prototype, 'togglePlayPause'); const component = mount( <VideoPlayer videoURL="http://localhost:3001/vid/local-video.mp4" volume={100} isPaused={false} /> ); component.setProps({ isPaused: true }); // 使用Sinon的断言方法 sinon.assert.called(toggleSpy); // 断言调用时的参数 sinon.assert.calledWith(toggleSpy, true); // 恢复原方法,避免污染组件原型 toggleSpy.restore(); });
额外优化提示
另外注意,你代码中使用的componentWillReceiveProps是React已经废弃的生命周期方法(React 16.3+),推荐换成componentDidUpdate来处理props更新后的逻辑,写法更符合现代React规范,测试逻辑基本不变:
componentDidUpdate(prevProps) { if (prevProps.isPaused !== this.props.isPaused) { this.togglePlayPause(this.props.isPaused); } }
内容的提问来源于stack exchange,提问作者DavidWorldpeace
相关产品推荐
相关产品推荐

