断言正在破坏 Mocha 测试中的异步功能

Posted

技术标签:

【中文标题】断言正在破坏 Mocha 测试中的异步功能【英文标题】:Assert Is Breaking Async Function in Mocha Test 【发布时间】:2015-03-26 16:33:04 【问题描述】:

我正在构建一个节点模块,并尽我所能对它进行单元测试。我已经设置了 mocha 和 chai 来进行测试处理。我在测试我的异步方法(返回承诺的方法)时遇到问题。

在下面的测试中,我正在“升级”对象上测试一个方法。

  it('Should return a list of versions for the default git repo', function (done) 
    fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG));

    var upgrade = new Upgrade(
      quiet: true
    );

    upgrade.getVersions().then(function (versions) 
      assert(versions && versions.length > 0, 'Should have at least one version.');
      assert.equal(1, 2); // this throws the exception which causes the test case not even exist
      done();
    , done);
  );

getVersions() 调用返回一个承诺,因为该方法是异步的。当承诺解决时,我想测试 versions 变量中返回的值。

assert(versions && versions.length > 0, 'Should have at least one version.'); 是实际测试。我添加了assert.equal(1, 2);,因为我注意到当测试失败时,测试用例甚至不会出现在测试列表中。

我假设 assert 调用引发了 Mocha 应该拾取的异常。但是它被困在了then 处理函数中。

这里发生了什么?为什么当该方法中的断言将失败时,它不会在列表中显示测试用例(它没有显示为失败;就像它不存在一样)?

【问题讨论】:

【参考方案1】:

问题的核心在于您拥有的代码本质上是:

try 
  var versions = upgrade.getVersions();
 catch (err)
  return done(err);


assert(versions && versions.length > 0, 'Should have at least one version.');
assert.equal(1, 2); // this throws the exception which causes the test case not even exist
done();

看看,应该清楚的是,如果断言抛出,那么都不回调将运行。

try 
  var versions = upgrade.getVersions();
  assert(versions && versions.length > 0, 'Should have at least one version.');
  assert.equal(1, 2); // this throws the exception which causes the test case not even exist
  done();
 catch (err)
  return done(err);

更像你想要的,那就是:

upgrade.getVersions().then(function (versions) 
  assert(versions && versions.length > 0, 'Should have at least one version.');
  assert.equal(1, 2); // this throws the exception which causes the test case not even exist
).then(done, done);

这将执行断言,然后将回调移动到辅助.then() 的节点,该辅助.then() 将始终处理错误。

也就是说,简单地将承诺返回为

return upgrade.getVersions().then(function (versions) 
  assert(versions && versions.length > 0, 'Should have at least one version.');
  assert.equal(1, 2); // this throws the exception which causes the test case not even exist
);

让 Mocha 在没有回调的情况下监控 Promise 本身。

【讨论】:

我不确定我理解为什么这个答案有效。原始代码基本上是: async().then(function() throw new Error(); // 如果这一行抛出,则传递给 .catch() 处理程序 done(); ).catch(done) // 将 done() 注册为错误处理程序。如果发生抛出,则不会执行 then() 处理程序中的 done() 调用,而是调用 .catch() 处理程序......仍然是 done 哎呀,cmets 不允许代码块并在 5 分钟后锁定。对不起,废话格式:( .then(fn, done) 不等于.then(fn).catch(done);,这是区别的核心。第一个如果fn抛出,这是一个未处理的错误,在第二个例子中,done被调用。 你的意思是说当.then()里面的代码失败时,它不会触发第二个参数? 是的,所以在问题中assert 抛出并且done 永远不会被调用,所以解决方案是移动done 处理程序以始终被调用,无论错误或其他情况。跨度> 【参考方案2】:

在您调用回调之前,测试不会显示在列表中,如果断言失败,则永远不会发生这种情况。您需要在最终承诺中调用 .catch(done),以确保始终调用 done

如果你给它一个超时值,测试显示出来,你应该这样做。

话虽如此,mocha 理解承诺。你根本不需要处理回调:

  it('Should return a list of versions for the default git repo', function () 
    fs.writeFileSync(appSetup.CONFIG_FILENAME, JSON.stringify(appSetup.DEFAULT_CONFIG));

    var upgrade = new Upgrade(
      quiet: true
    );

    return upgrade.getVersions().then(function (versions) 
      assert(versions && versions.length > 0, 'Should have at least one version.');
      assert.equal(1, 2);
    );
  );

【讨论】:

以上是关于断言正在破坏 Mocha 测试中的异步功能的主要内容,如果未能解决你的问题,请参考以下文章

异步 Mocha 测试(使用 Chai 断言库)应该失败,但被标记为通过

在整个 mocha 测试之前运行异步代码

使用 mocha 和 chaiAsPromised 测试异步函数时的断言错误

有没有办法让 Chai 使用异步 Mocha 测试?

如何使用异步路由进行 Ember 单元测试?

为啥我的测试用例通过但断言实际上在 mocha 中失败