簡體   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