首页 > 解决方案 > 直到超时才解决承诺的测试 sinon chai

问题描述

我们有一个简单的等待方法,在我们的节点应用程序中利用 Promise

exports.wait = (timeout) => {
  return new Promise((resolve) => {
    setTimeout(() => {
      resolve()
    }, timeout)
  });
};

我们尝试使用 sinon 和 chai 来测试这种行为。

我们设法使用 chai-as-promised 获得了正确的断言,但它只检查承诺的解决,而无法让我们测试真实的行为:

Promise 与计时器的结合确实让我们头疼。

这是我们最后一次尝试设置:

const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');
chai.use(require('sinon-chai'));
const chaiAsPromised = require('chai-as-promised');
chai.use(chaiAsPromised);

const wait = require('./wait').wait;

var clock;

before(() => {
  clock = sinon.useFakeTimers();
});

after(() => {
  clock.restore();
})

it('should not resolve until given time', (done) => {
  const promise = wait(100);
  let fulfilled = false;

  promise.then(() => {
    fulfilled = true;
    done();
  });

  clock.tick(99);
  expect(fulfilled).to.be.false;
  clock.tick(2);
  expect(fulfilled).to.be.true;
});

但是fulfilled永远不会被翻转为真,或者至少我们无法阅读它。

AssertionError:预期 false 为 true

那么如何在 chai - sinon 下将计时器与 promise 测试结合起来,以正确地利用我们的定时解决方案?

标签: javascriptpromisesinonchai

解决方案


您可以像这样测试问题中的代码:

const chai = require('chai');
const expect = chai.expect;
const sinon = require('sinon');

const wait = require('./wait').wait;

var clock;

before(() => {
  clock = sinon.useFakeTimers();
});

after(() => {
  clock.restore();
})

it('should not resolve until given time', async () => {  // <= async
  const promise = wait(100);
  let fulfilled = false;

  promise.then(() => {
    fulfilled = true;
    done();
  });

  clock.tick(99);
  await Promise.resolve();  // let any pending Promise callbacks run
  expect(fulfilled).to.be.false;  // Success!
  clock.tick(2);
  await Promise.resolve();  // let any pending Promise callbacks run
  expect(fulfilled).to.be.true;  // Success!
});

细节

假计时器将调度的回调setTimeout转换为同步调用。

Promise另一方面,回调在解决时在PromiseJobs 队列中排队,并且在当前正在执行的消息完成Promise之前不会运行。

在这种情况下,当前正在运行的消息是test,因此设置为的then回调测试完成之前不会运行。fulfilledtrue

您可以使用async测试函数并await Promise.resolve();在要暂停当前正在运行的消息并允许任何排队Promise的回调运行的任何时候调用。

有关使用 Fake Timers 的更多详细信息,Promises请参阅this answer which uses Jest,但概念是相同的。


推荐阅读