Javascript 摩卡咖啡-如何测试未兑现的承诺?

Javascript 摩卡咖啡-如何测试未兑现的承诺?,javascript,testing,promise,mocha.js,es6-promise,Javascript,Testing,Promise,Mocha.js,Es6 Promise,我正在测试一个返回承诺的函数。我想断言,在某些情况下,返回的承诺永远不会解决(不会解决也不会拒绝) 我如何用摩卡咖啡来测试这个 如果我运行以下命令: describe('under certain conditions', function () { let promise; beforeEach(function () { promise = new Promise((resolve, reject) => {}); }); it('should hang fo

我正在测试一个返回承诺的函数。我想断言,在某些情况下,返回的承诺永远不会解决(不会解决也不会拒绝)

我如何用摩卡咖啡来测试这个


如果我运行以下命令:

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
()在永不解析承诺和具有适当超时的引用承诺之间引入竞争:

const p1=新承诺((解析,拒绝)=>{});
常量p2=新承诺(函数(解析、拒绝){
setTimeout(解析,5*1000,'promise2');
});
承诺。种族([p1,p2])
.then(值=>{
console.log(值);
});可以工作,但在测试完成之前,您必须等待5秒钟。对于单元测试,5秒实在太长了

正如您所建议的,您可以将库集成到robertklep的解决方案中,以避免等待

(我还使用了a而不是字符串
'timeout'
,以防您的承诺碰巧与字符串
'timeout'
冲突)


定义“从不”。就像上面给出的例子-
新承诺((解决,拒绝)=>{})
永远不会解决问题,对吗?你真的不能。确保承诺永远不会得到解决的唯一方法是证明没有仍然引用它的
resolve
/
reject
函数处于活动状态。所以类似于
gc.collect();常数a=gc.memory();承诺=无效;gc.collect();常量b=gc.memory();返回a-b<0
可能会这样做,但它看起来不可靠。@Dayuoli您是否等待了无限长的时间来确定?@Dayuoli See(我认为我的语法错了,我也怀疑它是否有效,但您可以尝试)它是任何工具/库(不仅仅是Mocha)。您必须限制测试表示中的“永远”,即在标记测试用例通过/失败之前,您希望等待多长时间。由于摩卡咖啡的默认超时时间为2000毫秒,我将您的等待限制设置为1000毫秒。您可以随时调整mocha测试超时,但请确保您的等待时间应小于此值。您可能希望执行
承诺.比赛([delay(…),承诺.然后(()=>{throw…},()=>{throw…})]
而不是在事后处理分辨率,并比较
使用
符号时的
超时值+1。至于使用
lolex
,只有当实际用例依赖于某种超时时,这不是才有用吗?我假设OP并不是真的想测试
新承诺(()=>{})
永不解决,而是他们应用程序中的一些承诺。此外,它可能会干扰摩卡自身的计时。当您运行
lolex.install()
时,它将覆盖
setTimeout
的全局实例,此时,它将当前时间与其内部历元(从
0
开始)一起存储。当您运行
clock.tick()
时,它只需按该数量转发该历元,并检查是否需要执行任何回调。因此,也许
lolex
确实会干扰Mocha的计时功能,因为它会覆盖全局
setTimeout
,但在这种情况下,我认为这无关紧要,因为它不会超时,我们会在测试后恢复原始行为。(您可以在每次
/
之前
之后使用一个内部的
,以获得更高的粒度)(至少我认为
lolex
是这样工作的,我还没有看过源代码)
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');
      });
    });
  });
});