如何存储Promise以便我的测试可以同步运行?

时间:2015-09-29 06:52:27

标签: node.js unit-testing promise stubbing rsvp-promise

我试图通过对其中一个依赖项进行存根来对单元进行单元测试,在本例中为numbers

该模块的简化版如下:

UserManager

我正在对UserManager的// CodeHandler module.exports = function(UserManager) { return { oAuthCallback: function(req, res) { var incomingCode = req.query.code; var clientKey = req.query.key; UserManager.saveCode(clientKey, incomingCode) .then(function(){ res.redirect('https://test.tes'); }).catch(function(err){ res.redirect('back'); } ); } }; }; 函数进行存根,该函数返回saveCode,以便返回已解析的Promise,但当我Promise assert时已被调用,在断言res.redirect尚未被调用时唉。

单元测试的简化版本是:

res.redirect

如何正确地保留承诺,以使被测方法同步运行?

2 个答案:

答案 0 :(得分:2)

我使用sinon-stub-promise制定了解决方案。

describe('CodeHandler', function() {
  var req = {
    query: {
      code: 'test-code',
      key: 'test-state'
    }
  };
  var ch;
  var promise;

  var res = {
    redirect: function() {}
  };

  beforeEach(function() {
    promise = sinon.stub(UserManager, 'saveCode').returnsPromise();
    ch = CodeHandler(UserManager);
    sinon.stub(res, 'redirect');
  });

  afterEach(function() {
    UserManager.saveCode.restore();
    res.redirect.restore();
  });

  describe('can save code', function() {
    var expectedUrl = 'https://test.tes';

    beforeEach(function() {
        promise.resolves();
    });

    it('redirects to the expected URL', function(){
      ch.oAuthCallback(req, res);
      assert(res.redirect.calledWith(expectedUrl));
    });
  });

  describe('can not save code', function() {
    var expectedUrl = 'back';

    beforeEach(function() {
        promise.rejects();
    });

    it('redirects to the expected URL', function(){
      ch.oAuthCallback(req, res);
      assert(res.redirect.calledWith(expectedUrl));
    })
  })
});

这很有效。

答案 1 :(得分:1)

嗯,最简单的事情就是将其存根同步运行,因为这可能会改变执行顺序并使用Mocha内置的promises支持(或jasmine-as-promised)如果使用茉莉花)。

原因是可能会出现以下情况:

somePromise.then(function(){
    doB();
});
doA();

如果你使promises同步解决执行顺序 - 从而输出程序发生变化,使测试变得毫无价值。

相反,您可以使用测试语法:

describe("the test", () => { // use arrow functions, node has them and they're short
    it("does something", () => {
        return methodThatReturnsPromise().then(x => {
           // assert things about x, throws will be rejections here
           // which will cause a test failure, so can use `assert`
        });
    });
});

您可以对单行使用更轻的箭头语法,这使得测试更简洁:

describe("the test", () => { // use arrow functions, node has them and they're short
  it("does something", () =>
      methodThatReturnsPromise().then(x => {
         // assert things about x, throws will be rejections here
         // which will cause a test failure, so can use `assert`
      });
  );
});

在RSVP中,你不能根据我所知设置调度程序,因此无论如何都不可能同步测试事物,像bluebird这样的其他库允许你自己承担风险,但即使在让你这样做的图书馆可能不是最好的主意。