【问题标题】:How to assert in async function within Promise?如何在 Promise 中的异步函数中断言?
【发布时间】:2017-03-19 16:47:43
【问题描述】:

在使用 Mocha 进行单元测试时,我有这样的情况需要测试:

it('should assert true blah blah blah', function () {

  return doSomething() // <-- returns a Promise
    .then(function(value) {

      return setTimeout(function() {

        assert.equal(something, true);

      },1000);

    });

});

所以我有一个从函数返回的 Promise,然后我需要在解决 Promise 后在异步 setTimeout 中执行断言。无论如何,上面的代码似乎总是通过测试。事实上,setTimeout 似乎永远不会运行。如果我在setTimeout 中添加console.log,它永远不会打印出来。 Mocha 完成单元测试并继续前进。

测试这样的事情的正确方法是什么?我看到 Mocha 有某种 done() 方法,但我不确定我是否应该使用它。没完全看懂。

【问题讨论】:

  • 你是returning setTimeout(function) from .then()

标签: javascript unit-testing asynchronous promise mocha.js


【解决方案1】:

如果你向 Mocha 返回一个 Promise,它会在 Promise 解决时假定测试已经完成。

如果您在 Promise 解决后有一些基于非 Promise 的异步函数要测试,您可以使用 done 回调而不是返回一个 Promise:

it('should assert true blah blah blah', function (done) {

  doSomething()
    .then(function(value) {

      setTimeout(function() {

        assert.equal(something, true);
        done();

      },1000);

    })
    .catch(done);
});

请注意,您还应该包含一个catch,以便将任何拒绝的承诺传递给done 回调,因为 Mocha 可以理解 Node 样式的错误,并且如果收到错误,测试将失败。

或者,您可以使用完全基于 Promise 的方法,并可以创建一个 Promise 来包含您的异步函数:

it('should assert true blah blah blah', function () {

  return doSomething()
    .then(function(value) {

      return new Promise(function (resolve, reject) {

        setTimeout(function() {

          try {
            assert.equal(something, true);
            resolve();
          } catch (error) {
            reject(error);
          }

        },1000);

      });
    });
});

【讨论】:

    【解决方案2】:

    您不需要使用setTimeout() 来“等待”要解决的 Promise。相反,当 Promise 被解决时,.then() 将被调用。您只需使用value 或在那里做一些assert,就是这样。

    【讨论】:

    • setTimeout 不在那里等待 Promise 被解决。它的存在是出于特定原因,简化示例中没有解释。与缓存对象的到期有关,这是我正在测试的。问题中的示例被大大简化了。
    【解决方案3】:

    因为 Mocha 可以使用 intelligently with functions that return Promises,您还可以使用新的 async/await 语法,它隐式返回 Promises!

    import 'babel-polyfill';
    
    it('should assert true blah blah blah', async function () {
      // `doSomething` is a function that returns a Promise
      // `something` will be the resolved value
      let something = await doSomething();
      assert.equal(something, true);
    });

    需要进行一些设置,但考虑到您的测试代码最终看起来多么漂亮和平坦,我认为这是值得的。而且写起来超级简单。

    您可能需要以下软件包——es2015es2016 在此处是可选的,但如果您要编译测试代码,不妨包括这些。无论如何,你最终都会想要它们。 babel-register 用于 require 钩子,babel-polyfill 用于 regenerator 运行时。

    $ npm install --save-dev babel-cli           \
                             babel-register      \
                             babel-polyfill      \
                             babel-preset-es2015 \
                             babel-preset-es2016 \
                             babel-preset-es2017
    

    你的 .babelrc

    {
      "presets": ["es2015", "es2016", "es2017"]
    }
    

    你的 package.json

    {
      "scripts": {
        "test": "mocha --compilers js:babel-register"
      }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-01-22
      • 2016-06-14
      • 2017-05-18
      • 1970-01-01
      • 2017-10-29
      • 2020-08-13
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多