简体   繁体   English

sinon spy 未在具有异步功能的存根中调用

[英]sinon spy is not called in a stub with async function

Using sinon and enzyme I wanna test the following component:使用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>);
  }
}

If I just check endApy.called , it's always false.如果我只检查endApy.called ,它总是错误的。 But wrapping it in a setTimeout will make it pass.但是将其包装在setTimeout中将使其通过。 Why console.log() is always called but not the props.end ?为什么console.log()总是被调用而不是props.end Why setTimeout fixes it?为什么setTimeout修复它? Is there a better way of doing this?有没有更好的方法来做到这一点?

// 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();
});

Api.get is async function and it returns a promise, so to emulate async call in test you need to call resolves function not returns : Api.get是异步函数,它返回一个承诺,因此要在测试中模拟异步调用,您需要调用resolves函数而不returns

Causes the stub to return a Promise which resolves to the provided value.使存根返回一个解析为提供的值的 Promise。 When constructing the Promise, sinon uses the Promise.resolve method.在构建 Promise 时, sinon 使用 Promise.resolve 方法。 You are responsible for providing a polyfill in environments which do not provide Promise.您有责任在不提供 Promise 的环境中提供 polyfill。

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

your console.log(data) always happens because your Promise does resolve, it just does so after the test has finished, which is why the assertion fails.您的console.log(data)总是发生,因为您的 Promise 确实解决了,它只是在测试完成后才解决,这就是断言失败的原因。

By wrapping it in a setTimeout you create another event in the loop, which allows your Promise to resolve before the test finishes, meaning that your assertion will now pass.通过将它包装在 setTimeout 中,您可以在循环中创建另一个事件,这允许您的 Promise 在测试完成之前解决,这意味着您的断言现在将通过。

This is a fairly common problem when unit testing asynchronous code.在单元测试异步代码时,这是一个相当普遍的问题。 Often resolved in wrapping the assertions in setImmediate and calling done from the callback of setImmediate .通常通过将断言包装在setImmediate并从setImmediate的回调中调用donesetImmediate

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

I ran into a similar problem with a spy and using await Promise.all(spy.returnValues) worked fine for me.我遇到了一个与间谍类似的问题,使用await Promise.all(spy.returnValues)对我来说效果很好。 This resolves all the promises and afterwards I can check spy.called .这解决了所有的承诺,之后我可以检查spy.called . spy.called

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM