web-dev-qa-db-ja.com

変更をテストするReactコンポーネントの状態と酵素を使用したインスタンスメソッドのスパイ

Reactで画像をスムーズにロードするためのラッパーコンポーネントに取り組んでいます。私はコンポーネントを単体テストするために酵素をモカ、チャイ、シノンと共に使用しています。ここでのテストでは、私はそれをテストしようとしています:

  1. コンポーネントの状態は、画像が読み込まれたときに更新されます

  2. コンポーネントのonLoadインスタンスメソッドが呼び出されました

 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>);

    }}

より良いコンテキストの完全なコードを見てみましょう:

14
vamsiampolu

sinonに依存せずにこれをテストできます。 onLoadおよびonFireイベントリスナーが呼び出されることを想定して、テストはimgloadおよびerrorイベントを起動するかどうかを確認します。

代わりに、simulateimgを使用して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 にあります。

16
vamsiampolu

このアプローチで私が目にする主な問題は、状態が内部的なものであり、コンポーネントの外部で知られるべきものではないということです。これで、状態情報(この場合は「ステータス」)をテストにリークしています。

これを行うと、「ブラックボックステスト」を実行しないことになります。これは、最も価値のあるタイプのテストです。コンポーネントの実装の詳細を漏らしています。言い換えれば、「カプセル化」は非常に考慮されるべきです。

これをテストするより良い方法があるかもしれません。たとえば、プレゼンテーションコンポーネントもエクスポートできます。これは、テストする必要がある状態の部分を小道具として受け取ります。または、酵素 find メソッドでステータスが「LOADED」の場合にレンダリングされる要素を探します。

0
darmis