使用酶

时间:2016-11-21 17:02:46

标签: javascript reactjs sinon enzyme chai-enzyme

我正在开发一个包装器组件,用于在React中平滑地加载图像。我使用含有mocha,chai和sinon的酶对我的组件进行单元测试。在这里的测试中,我试图测试:

  1. 组件的状态在图像加载后更新

  2. 组件上的onLoad实例方法名为

  3. const wrapper = shallow( );
    
    const onLoad = wrapper.find('img').props().onLoad;
    const onLoadSpy = sinon.spy(onLoad); wrapper.update();
    const status = wrapper.state().status;
    expect(onLoadSpy).to.have.been.called;
    expect(status).to.equal('LOADED');
    

    我发现状态更新既不会被酶反映,也不会更新onLoad间谍的通话计数。这是测试的相应代码:

    export default class Image extends Component {
      constructor(props) {
        super(props);
        if (props.src != null && typeof props.src === 'string') {
          this.state = {
            status: LOADING,
          };
        } else {
          this.state = {
            status: PENDING,
          };
        }
        this.onLoad = this.onLoad.bind(this);
      }
    
      onLoad() {
        this.setState({
          status: LOADED,
        });
      }
    
      render() {
        //lots of code above the part we care about
        const defaultImageStyle = style({
          opacity: 0,
          transisition: 'opacity 150ms ease',
        });
    
        const loadedImageStyle = style({
          opacity: 1,
        });
    
        let imageStyle = defaultImageStyle;
    
        if (this.state.status === LOADED) {
          imageStyle = merge(defaultImageStyle, loadedImageStyle);
        } else {
          imageStyle = defaultImageStyle;
        }
    
    
        let image;
        if (alt != null) {
          image = (<img
            className={imageStyle}
            src={src}
            width={width}
            height={height}
            alt={alt}
            onLoad={this.onLoad}
          />);
        } else {
          image = (<img
            className={imageStyle}
            src={src}
            width={width}
            height={height}
            role="presentation"
            onLoad={this.onLoad}
          />);
        }
    
        let statusIndicator = null;
        if (this.state.status === LOADING) {
          statusIndicator = (<div className={loadingStyle}></div>);
        }
    
        return (<div className={wrapperStyle}>
          {statusIndicator}
          {image}
        </div>);
    
        }}
    

    要查看完整代码以获得更好的上下文:

2 个答案:

答案 0 :(得分:14)

可以在不依赖sinon的情况下对此进行测试。通过期望调用onLoadonFire事件侦听器,测试会检查img是否触发loaderror事件。

相反,simulate img使用enzyme的事件并检查是否发生了适当的状态转换:

it('has a state of LOADED if a good src prop is supplied', () => {
  const wrapper = shallow(<Image 
    src="anyString.jpg"
    width={300}
    height={300}
  />);

  const img = wrapper.find('img');
  img.simulate('load');
  const status = wrapper.state().status;
  expect(status).to.equal('LOADED');
});

这也消除了mount组件的需要。可以找到更新的测试here

答案 1 :(得分:0)

我用这种方法看到的主要问题是状态是一个内部事物,而不是组件外部不应该知道的事物。现在,您正在将状态信息(在这种情况下为“状态”)泄漏到测试中。

这样做意味着您没有在进行“黑盒测试”,这是最有价值的测试类型。您正在泄漏该组件的实现细节。换句话说,应该高度考虑“封装”。

也许有更好的方法对此进行测试。例如,您也可以导出一个表示性组件,该组件将需要测试的状态部分作为道具。或者使用酶find方法寻找状态为“ LOADED”时将呈现的元素。