web-dev-qa-db-ja.com

シノンスパイは非同期関数を持つスタブで呼び出されません

sinonenzymeを使用して次のコンポーネントをテストしたいと思います。

_// Apple.js
class Apple extends Component {

  componentDidMount = () => {

    this.props.start();
    Api.get()
      .then(data => {
        console.log(data); // THIS IS ALWAYS CALLED
        this.props.end();
      });
  }

  render () {
    return (<div></div>);
  }
}
_

_endApy.called_をチェックするだけでは、常にfalseです。ただし、setTimeoutでラップすると合格になります。なぜconsole.log()は常に呼び出されますが、_props.end_は呼び出されないのですか?なぜsetTimeoutがそれを修正するのですか?これを行うためのより良い方法はありますか?

_// Apple.test.js
import sinon from 'sinon';
import { mount } from 'enzyme';
import Api from './Api';
import Apple from './Apple';


test('should call "end" if Api.get is successfull', t => {
  t.plan(2);
    sinon
        .stub(Api, 'get')
        .returns(Promise.resolve());

    const startSpy = sinon.spy();
    const endApy = sinon.spy();

    mount(<Apple start={ startSpy } end={ endApy } />);

    t.equal(startSpy.called, true);                    // ALWAYS PASSES 
    t.equal(endSpy.called, true);                      // ALWAYS FAILS
    setTimeout(() => t.equal(endApy.called, true));    // ALWAYS PASSES

    Api.get.restore();
});
_
5
norbertpy

Api.getは非同期関数であり、promiseを返すため、テストで非同期呼び出しをエミュレートするには、resolvesではなくreturns関数を呼び出す必要があります。

指定された値に解決されるPromiseをスタブに返します。 Promiseを構築するとき、sinonはPromise.resolveメソッドを使用します。あなたは、Promiseを提供しない環境でポリフィルを提供する責任があります。

sinon
  .stub(Api, 'get')
  .resolves('ok');
13
alexmac

console.log(data)は、Promiseが解決するために常に発生します。解決するのは、テストが終了した直後です。これが、アサーションが失敗する理由です。

これをsetTimeoutでラップすることにより、ループ内に別のイベントを作成します。これにより、テストが終了する前にPromiseを解決できます。つまり、アサーションは合格になります。

これは、非同期コードを単体テストする場合のかなり一般的な問題です。多くの場合、アサーションをsetImmediateでラップし、doneのコールバックからsetImmediateを呼び出すことで解決されます。

https://stackoverflow.com/a/43855794/60249

2
AHB