我怎样才能正确地用摩卡和印度茶来测试我的承诺呢?

下面的测试结果很奇怪:

it('Should return the exchange rates for btc_ltc', function(done) {
var pair = 'btc_ltc';


shapeshift.getRate(pair)
.then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
done();
})
.catch(function(err){
//this should really be `.catch` for a failed request, but
//instead it looks like chai is picking this up when a test fails
done(err);
})
});

我应该如何正确处理被拒绝的承诺(并测试它) ?

我应该如何正确处理一个失败的测试(即: expect(data.rate).to.have.length(400);

下面是我正在测试的实现:

var requestp = require('request-promise');
var shapeshift = module.exports = {};
var url = 'http://shapeshift.io';


shapeshift.getRate = function(pair){
return requestp({
url: url + '/rate/' + pair,
json: true
});
};
116365 次浏览

最简单的方法就是使用 Mocha 在最近版本中内置的承诺支持:

it('Should return the exchange rates for btc_ltc', function() { // no done
var pair = 'btc_ltc';
// note the return
return shapeshift.getRate(pair).then(function(data){
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});// no catch, it'll figure it out since the promise is rejected
});

或者使用现代 Node 和 sync/wait:

it('Should return the exchange rates for btc_ltc', async () => { // no done
const pair = 'btc_ltc';
const data = await shapeshift.getRate(pair);
expect(data.pair).to.equal(pair);
expect(data.rate).to.have.length(400);
});

由于这种方法是承诺端到端,它更容易测试,你不必考虑奇怪的情况下,你正在考虑像奇怪的 done()调用无处不在。

这是一个优势,摩卡相对于其他图书馆,如茉莉花目前。您可能还想检查 正如承诺的那样,这将使它更容易(没有 .then) ,但我个人更喜欢当前版本的清晰和简单

正如已经指出的 给你,新版本的 Mocha 已经具有承诺感知能力。但是,既然 OP 特别问到了 Chai,那么只能指出 chai-as-promised软件包为测试承诺提供了简洁的语法:

用的是说好的印度茶

以下是你如何使用 chai-as- 承諾來測試 resolvereject病例的方法:

var chai = require('chai');
var expect = chai.expect;
var chaiAsPromised = require("chai-as-promised");
chai.use(chaiAsPromised);


...


it('resolves as promised', function() {
return expect(Promise.resolve('woof')).to.eventually.equal('woof');
});


it('rejects as promised', function() {
return expect(Promise.reject('caw')).to.be.rejectedWith('caw');
});

没有说好的印度茶

为了更清楚地说明要测试的内容,这里有一个同样的例子,没有像承诺的那样使用 chai:

it('resolves as promised', function() {
return Promise.resolve("woof")
.then(function(m) { expect(m).to.equal('woof'); })
.catch(function(m) { throw new Error('was not supposed to fail'); })
;
});


it('rejects as promised', function() {
return Promise.reject("caw")
.then(function(m) { throw new Error('was not supposed to succeed'); })
.catch(function(m) { expect(m).to.equal('caw'); })
;
});

以下是我的看法:

  • 使用 async/await
  • 不需要额外的印度茶模块
  • “疯狂程序员”在上文中指出,这样可以避免捕获问题

一种延迟的承诺函数,如果延迟为0,则该函数失效:

const timeoutPromise = (time) => {
return new Promise((resolve, reject) => {
if (time === 0)
reject({ 'message': 'invalid time 0' })
setTimeout(() => resolve('done', time))
})
}


//                     ↓ ↓ ↓
it('promise selftest', async () => {


// positive test
let r = await timeoutPromise(500)
assert.equal(r, 'done')


// negative test
try {
await timeoutPromise(0)
// a failing assert here is a bad idea, since it would lead into the catch clause…
} catch (err) {
// optional, check for specific error (or error.type, error. message to contain …)
assert.deepEqual(err, { 'message': 'invalid time 0' })
return  // this is important
}
assert.isOk(false, 'timeOut must throw')
log('last')
})

阳性测试 相当简单,意外失败(由 500→0模拟)将自动失败测试,因为被拒绝的承诺升级。

负面测试 使用 try-catch-idea。但是: 只有在 catch 子句之后才会发生对不想要的传球的“抱怨”(这样,它就不会最终出现在 catch ()子句中,从而引发进一步的误导性错误。

要使这个策略生效,必须从 catch 子句返回测试。如果您不想测试任何其他内容,请使用另一个 it ()-block。

有一个更好的解决方案。只需在 catch 块中返回已完成的错误。

// ...


it('fail', (done) => {
// any async call that will return a Promise
ajaxJson({})
.then((req) => {
expect(1).to.equal(11); //this will throw a error
done(); //this will resove the test if there is no error
}).catch((e) => {
done(e); //this will catch the thrown error
});
});

这个测试将失败,并带有以下消息: AssertionError: expected 1 to equal 11