在摩卡/Chai中测试拒绝的承诺



我有一个拒绝承诺的类:

Sync.prototype.doCall = function(verb, method, data) {
  var self = this;
  self.client = P.promisifyAll(new Client());
  var res = this.queue.then(function() {
    return self.client.callAsync(verb, method, data)
      .then(function(res) {
        return;
      })
      .catch(function(err) {    
        // This is what gets called in my test    
        return P.reject('Boo');
      });
  });
  this.queue = res.delay(this.options.throttle * 1000);
  return res;
};
Sync.prototype.sendNote = function(data) {
  var self = this;
  return self.doCall('POST', '/Invoice', {
    Invoice: data
  }).then(function(res) {
    return data;
  });
};

在我的测试:

return expect(s.sendNote(data)).to.eventually.be.rejectedWith('Boo');

然而,当测试通过时,它将错误抛出到控制台。

未处理拒绝错误:Boo…

对于非承诺错误,我使用bind来测试,以防止抛出错误,直到Chai可以包装和测试:

return expect(s.sendNote.bind(s, data)).to.eventually.be.rejectedWith('Boo');

但是这不起作用,返回:

TypeError: [Function] is not a thenable.

正确的测试方法是什么?

(免责声明:即使对于不使用Bluebird的人来说,这也是一个很好的问题。我在这里贴了一个类似的答案;这个答案将适用于不使用Bluebird的人。

与chai-as-promised

下面是如何使用chai-as- Promise来测试一个Promise的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-as-promised

如果没有chai-as-promise,你也可以做到同样的事情,像这样:

it('resolves as promised', function() {
  return Promise.resolve("woof")
    .then(function(m) { expect(m).to.equal('woof'); })
    .catch(function(e) { throw e })  // use error thrown by test suite
           ;
});
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'); })
            ;
});

我个人使用这个成语:

it('rejects as promised', function() {
    return Promise.reject("caw")
        .then(
          (m) => { assert.fail('was not supposed to succeed'); }
          (m) => { /* some extra tests here */ }
        );
});

这是then(onFulfilled, onRejected)(2个参数)可以合法使用的罕见情况之一。

如果像其他答案中建议的那样链接.then(reject).catch(onRejected),那么每次都要输入catch处理程序,因为它也会捕获在前面的then处理程序中产生的拒绝——如果您不够仔细地检查这种可能性,可能会导致常绿测试。

你得到错误是因为sendNote被拒绝而你没有捕捉到它

试题:

var callPromise = self.doCall('POST', '/Invoice', {
  Invoice: data
}).then(function(res) {
  return data;
});
callPromise.catch(function(reason) {
  console.info('sendNote failed with reason:', reason);
});
return callPromise;

看起来您还必须将现有的catch块移出:

var res = this.queue.then(function() {
  return self.client.callAsync(verb, method, data)
    .then(function(res) {
      return;
    });
  }).catch(function(err) {    
    // This is what gets called in my test    
    return P.reject('Boo');
  });

泛型辅助函数:

import { assert } from 'chai'
const assertThrowsAsync = async(fn, expectedMessage) => {
    try {
        await fn()
    } catch (err) {
        if (expectedMessage) {
            assert.include(err.message, expectedMessage, `Function failed as expected, but could not find message snippet '${expectedMessage}'`)
        }
        return
    }
    assert.fail('function did not throw as expected')
}

这样调用:

describe('demo', () => {
    it('negative: inacceptable path', async() => {
        await assertThrowsAsync(async() => {
            await someFuntionOfMine({}, ['/really/bad/path'])
        }, 'acceptable path')
    })
    ...

相关内容

  • 没有找到相关文章

最新更新