繁体   English   中英

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

[英]How can I stub a Promise such that my test can be run synchronously?

我试图通过对其中一个依赖项(在本例中为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');
        }
      );
    }
  };
};

我捻熄的UserManager的saveCode它返回一个函数Promise ,使得它返回一个解决的承诺,但是当我assertres.redirect被调用,唉,在断言的时间res.redirect尚未被调用。

单元测试的简化版本是:

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

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

  var expectedUrl = 'https://test.tes';
  var ch;

  beforeEach(function() {
    sinon.stub(UserManager, 'saveCode').returns(
      new RSVP.Promise(function(resolve, reject){
        resolve();
      })
    );

    sinon.stub(res, 'redirect');

    ch = CodeHandler(UserManager);
  });

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

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

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

我已经使用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));
    })
  })
});

这非常有效。

好吧,最简单的事情就是不要将它存根同步运行,因为这可能会改变执行顺序并使用Mocha内置的promises支持(如果使用jasmine则使用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这样的其他库允许你自己承担风险,但即使在允许你这样做的库中它也可能不是最好的主意。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM