将 mocha+chai 与 co 一起使用
Using mocha+chai together with co
当 chai.expect
断言失败时,
他们通常没有通过测试
负面结果被添加到报告中
对于测试运行程序(在本例中为 mocha
)。
但是,当我使用使用 co.wrap()
包装的生成器函数时,
如下所示,
奇怪的事情发生了:
当断言通过时,一切运行正常。
然而,当断言失败时,测试超时。
co
如何与mocha
+chai
一起使用?
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();
}
});
});
解决方案:
问题的出现是由于 co.wrap()
吞噬了 expect()
抛出的异常,不允许它冒泡到 mocha
找到它所需的位置,正如所指出的@Bergi 下面。
解决方案是使用 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);
co.wrap
从生成器中捕获异常,并拒绝返回的承诺。它 "swallows" 从 continueTest
中的断言中抛出的错误。顺便说一句,您可以直接调用 co(…)
.
而不是使用 .wrap
并立即调用它
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);
});
此处代码的根本问题是您试图在 suptertest 的 end
CPS 回调中屈服;由于此函数不是生成器函数 yield
无法使用,您的异常将消失在以太中,如您所见。
直接使用 co.wrap
是正确的方式(当使用 co 时)给 mocha 一个承诺,它可以用来跟踪使用生成器函数和 yield
的测试的成功或失败异步流控制,你只需要序列化你的测试,以便数据库检查在超级测试之后运行。
您的解决方案通过使用 co
将生成器函数转换为承诺来解决此问题,然后使用该承诺 "convert" 通过其 catch
返回到摩卡的 CPS 样式异步函数调用 done
如果数据库检查抛出:
co(function *() {
var dbFoo = yield foos.findOne({
id: input.id,
});
continueTest(dbFoo);
}).catch(done);
拯救的承诺
好消息是 supertest 也支持 promises,这可以更简单地完成。
您缺少的重要部分(如 Bergi 的回答中所示)是承诺、生成器函数,很快 async/await 可以协同工作。在这种情况下我们可以利用这个在生成器函数内部直接产生一个promise,supertest的promise。
这会直接在该测试生成器函数中保留数据库检查,其中任何异常都将由 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);
}));
当 chai.expect
断言失败时,
他们通常没有通过测试
负面结果被添加到报告中
对于测试运行程序(在本例中为 mocha
)。
但是,当我使用使用 co.wrap()
包装的生成器函数时,
如下所示,
奇怪的事情发生了:
当断言通过时,一切运行正常。
然而,当断言失败时,测试超时。
co
如何与mocha
+chai
一起使用?
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();
}
});
});
解决方案:
问题的出现是由于 co.wrap()
吞噬了 expect()
抛出的异常,不允许它冒泡到 mocha
找到它所需的位置,正如所指出的@Bergi 下面。
解决方案是使用 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);
co.wrap
从生成器中捕获异常,并拒绝返回的承诺。它 "swallows" 从 continueTest
中的断言中抛出的错误。顺便说一句,您可以直接调用 co(…)
.
.wrap
并立即调用它
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);
});
此处代码的根本问题是您试图在 suptertest 的 end
CPS 回调中屈服;由于此函数不是生成器函数 yield
无法使用,您的异常将消失在以太中,如您所见。
直接使用 co.wrap
是正确的方式(当使用 co 时)给 mocha 一个承诺,它可以用来跟踪使用生成器函数和 yield
的测试的成功或失败异步流控制,你只需要序列化你的测试,以便数据库检查在超级测试之后运行。
您的解决方案通过使用 co
将生成器函数转换为承诺来解决此问题,然后使用该承诺 "convert" 通过其 catch
返回到摩卡的 CPS 样式异步函数调用 done
如果数据库检查抛出:
co(function *() {
var dbFoo = yield foos.findOne({
id: input.id,
});
continueTest(dbFoo);
}).catch(done);
拯救的承诺
好消息是 supertest 也支持 promises,这可以更简单地完成。
您缺少的重要部分(如 Bergi 的回答中所示)是承诺、生成器函数,很快 async/await 可以协同工作。在这种情况下我们可以利用这个在生成器函数内部直接产生一个promise,supertest的promise。
这会直接在该测试生成器函数中保留数据库检查,其中任何异常都将由 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);
}));