Mocha - 如何测试未解决的承诺?
Mocha - How to test for unsettled promise?
我正在测试一个 returns 承诺的功能。我想断言,在某些情况下,返回的承诺永远不会解决(既不解决也不拒绝)。
我如何用 Mocha 测试这个?
如果我运行以下:
describe('under certain conditions', function () {
let promise;
beforeEach(function () {
promise = new Promise((resolve, reject) => {});
});
it('should hang forever', function () {
return promise;
});
});
我收到以下错误:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves
让我们首先说明,实际上,无法验证承诺 永远不会 解决:在某些时候,您必须确定承诺花了太长时间稳定,并假设在那之后它永远不会稳定。
这里有一个将那个点放在 5 秒的解决方案:
it('should hang forever', function() {
// Disable Mocha timeout for this test.
this.timeout(0);
// Wait for either a timeout, or the promise-under-test to settle. If the
// promise that settles first is not the timeout, fail the test.
return Promise.race([
new Promise(resolve => setTimeout(resolve, 5000, 'timeout')),
promise.then(
() => { throw Error('unexpectedly resolved') },
() => { throw Error('unexpectedly rejected') }
)
]);
});
试试这个:
describe('under certain conditions', function () {
let promise;
beforeEach(function () {
promise = new Promise((resolve, reject) => {
// promise.reject();
});
});
it('should hang forever', function (done) {
const onRejectOrResolve = () => {
done(new Error('test was supposed to hang'));
};
promise
.then(onRejectOrResolve)
.catch(onRejectOrResolve);
setTimeout(() => {
done();
}, 1000);
});
});
您可以使用 Promise.race
(MDN):
在永不解析的承诺和具有合适超时的参考承诺之间引入竞争
const p1 = new Promise((resolve, reject) => { });
const p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 5 * 1000, 'promise2');
});
Promise.race([p1, p2])
.then(value => {
console.log(value);
});
robertklep's 有效,但您必须等待 5 秒才能完成测试。对于单元测试,5 秒太长了。
正如您所建议的,您可以将 lolex
库集成到 robertklep 的解决方案中,以避免等待。
(我也在使用 Symbol
而不是字符串 'timeout'
,以防你的 promise 巧合地解析为字符串 'timeout'
)
import { install } from 'lolex';
describe('A promise', function () {
let clock;
before(function () { clock = install() });
after(function () { clock.uninstall() });
describe('under certain conditions', function () {
const resolvedIndicator = Symbol('resolvedIndicator');
const forever = 600000; // Defining 'forever' as 10 minutes
let promise;
beforeEach(function () {
promise = Promise.race([
new Promise(() => {}), // Hanging promise
new Promise(resolve => setTimeout(resolve, forever, resolvedIndicator)),
]);
});
it('should hang forever', function () {
clock.tick(forever);
return promise.then((val) => {
if (val !== resolvedIndicator) {
throw Error('Promise should not have resolved');
}
}, () => {
throw Error('Promise should not have rejected');
});
});
});
});
我正在测试一个 returns 承诺的功能。我想断言,在某些情况下,返回的承诺永远不会解决(既不解决也不拒绝)。
我如何用 Mocha 测试这个?
如果我运行以下:
describe('under certain conditions', function () {
let promise;
beforeEach(function () {
promise = new Promise((resolve, reject) => {});
});
it('should hang forever', function () {
return promise;
});
});
我收到以下错误:
Error: Timeout of 2000ms exceeded. For async tests and hooks, ensure "done()" is called; if returning a Promise, ensure it resolves
让我们首先说明,实际上,无法验证承诺 永远不会 解决:在某些时候,您必须确定承诺花了太长时间稳定,并假设在那之后它永远不会稳定。
这里有一个将那个点放在 5 秒的解决方案:
it('should hang forever', function() {
// Disable Mocha timeout for this test.
this.timeout(0);
// Wait for either a timeout, or the promise-under-test to settle. If the
// promise that settles first is not the timeout, fail the test.
return Promise.race([
new Promise(resolve => setTimeout(resolve, 5000, 'timeout')),
promise.then(
() => { throw Error('unexpectedly resolved') },
() => { throw Error('unexpectedly rejected') }
)
]);
});
试试这个:
describe('under certain conditions', function () {
let promise;
beforeEach(function () {
promise = new Promise((resolve, reject) => {
// promise.reject();
});
});
it('should hang forever', function (done) {
const onRejectOrResolve = () => {
done(new Error('test was supposed to hang'));
};
promise
.then(onRejectOrResolve)
.catch(onRejectOrResolve);
setTimeout(() => {
done();
}, 1000);
});
});
您可以使用 Promise.race
(MDN):
const p1 = new Promise((resolve, reject) => { });
const p2 = new Promise(function(resolve, reject) {
setTimeout(resolve, 5 * 1000, 'promise2');
});
Promise.race([p1, p2])
.then(value => {
console.log(value);
});
robertklep's
正如您所建议的,您可以将 lolex
库集成到 robertklep 的解决方案中,以避免等待。
(我也在使用 Symbol
而不是字符串 'timeout'
,以防你的 promise 巧合地解析为字符串 'timeout'
)
import { install } from 'lolex';
describe('A promise', function () {
let clock;
before(function () { clock = install() });
after(function () { clock.uninstall() });
describe('under certain conditions', function () {
const resolvedIndicator = Symbol('resolvedIndicator');
const forever = 600000; // Defining 'forever' as 10 minutes
let promise;
beforeEach(function () {
promise = Promise.race([
new Promise(() => {}), // Hanging promise
new Promise(resolve => setTimeout(resolve, forever, resolvedIndicator)),
]);
});
it('should hang forever', function () {
clock.tick(forever);
return promise.then((val) => {
if (val !== resolvedIndicator) {
throw Error('Promise should not have resolved');
}
}, () => {
throw Error('Promise should not have rejected');
});
});
});
});