0

chai.expect断言失败时,它们通常会导致测试失败,并且否定结果会被添加到测试运行器的报告中(在这种情况下mocha)。

但是,当我使用使用 包装的生成器函数时co.wrap(),如下所示,会发生一些奇怪的事情:当断言通过时,一切都运行得很好。但是,当断言失败时,测试会超时。

如何与+co一起使用?mochachai


it('calls API and then verifies database contents', function(done) {
  var input = {
    id: 'foo',
    number: 123,
  };
  request
    .post('/foo')
    .send(input)
    .expect(201)
    .expect({
      id: input.id,
      number: input.number,
    })
    .end(function(err) {
      if (!!err) {
        return done(err);
      }

      // Now check that database contents are correct
      co.wrap(function *() {
        var dbFoo = yield foos.findOne({
          id: input.id,
        });
        continueTest(dbFoo);
      })();

      function continueTest(dbFoo) {
        //NOTE when these assertions fail, test times out
        expect(dbFoo).to.have.property('id').to.equal(input.id);
        expect(dbFoo).to.have.property('number').to.equal(input.number);
        done();
      }
    });
});

解决方案:

正如下面@Bergi 所指出的,问题是由于co.wrap()吞下 引发的异常而出现的expect(),不允许它冒泡到需要找到它的位置。mocha

解决方案是使用co()而不是co.wrap(),并添加.catch()并传递done回调,如下所示。

      // Now check that database contents are correct
      co(function *() {
        var dbFoo = yield foos.findOne({
          id: input.id,
        });
        continueTest(dbFoo);
      }).catch(done);
4

2 回答 2

2

co.wrap从生成器中捕获异常,并拒绝返回的承诺。它“吞下”从continueTest. 顺便说一句,.wrap您可以直接调用co(…).

co(function*() {
    …
}).then(done, done); // fulfills with undefined or rejects with error

或者

co(function*() {
    …
    done();
}).catch(done);

顺便说一句,要正确使用 co,您可以将所有异步函数放在一个生成器中:

it('calls API and then verifies database contents', function(done) {
  co(function*() {
    var input = {
      id: 'foo',
      number: 123,
    };
    yield request
      .post('/foo')
      .send(input)
      .expect(201)
      .expect({
        id: input.id,
        number: input.number,
      })
      .endAsync(); // assuming you've promisified it

    // Now check that database contents are correct
    var dbFoo = yield foos.findOne({
      id: input.id,
    });

    expect(dbFoo).to.have.property('id').to.equal(input.id);
    expect(dbFoo).to.have.property('number').to.equal(input.number);

  }).then(done, done);
});
于 2015-08-12T00:22:18.267 回答
1

您的代码的根本问题是您试图在 suptertest 的endCPS 回调中让步;因为这个函数不是生成器函数yield,所以不能使用,你的异常会消失在以太中,正如你所看到的。

直接使用co.wrap是正确的方法(当使用 co 时)给 mocha 一个承诺,它可以用来跟踪使用生成器函数和yield异步流控制的测试的成功或失败,你只需要序列化你的测试,以便数据库超测后检查运行。

您的解决方案通过使用co将生成器函数转换为承诺来解决此问题,然后使用该承诺“转换”回 mocha 的 CPS 样式异步,方法是使用其catch函数done在 db 检查抛出时调用:

co(function *() {
    var dbFoo = yield foos.findOne({
      id: input.id,
    });
    continueTest(dbFoo);
}).catch(done);

承诺救援

好消息是 supertest 也支持 Promise,这可以更简单地完成。

您缺少的重要部分(如 Bergi 的回答中所示)是承诺、生成器函数以及很快的 async/await 可以一起工作。在这种情况下,我们可以利用这一点在生成器函数中直接产生一个承诺,即超测的承诺。

这使 db check 直接在该测试生成器函数中进行,任何异常都将被正确处理co.wrap并作为拒绝传递给 mocha。

现在,该测试被整齐地序列化,没有任何 CPS 碎屑。这难道不是 js 中这些新的异步特性的承诺吗?


it('calls API and then verifies database contents', co.wrap(function*() {
  var input = {
    id: 'foo',
    number: 123,
  };

  yield request
    .post('/foo')
    .send(input)
    .expect(201)
    .expect({
      id: input.id,
      number: input.number,
    });

  // Now check that database contents are correct
  var dbFoo = yield foos.findOne({
    id: input.id,
  });

  expect(dbFoo).to.have.property('id').to.equal(input.id);
  expect(dbFoo).to.have.property('number').to.equal(input.number);  
}));

于 2017-02-27T11:40:40.087 回答