【问题标题】:Assert Is Breaking Async Function in Mocha Test断言正在破坏 Mocha 测试中的异步功能
【发布时间】: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 处理函数中。

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

【问题讨论】:

    标签: node.js testing promise mocha.js


    【解决方案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);
        });
      });
    

    【讨论】:

      猜你喜欢
      • 2013-03-16
      • 2019-02-19
      • 2017-05-27
      • 2011-06-23
      • 1970-01-01
      • 1970-01-01
      • 2015-10-29
      • 2012-09-29
      • 1970-01-01
      相关资源
      最近更新 更多