在NodeJS中,如何测试解析POST API请求的类方法发出的事件?

时间:2017-03-26 07:38:29

标签: javascript node.js unit-testing mocha chai

基本上,我正在测试一个StreamReader,它在POST请求执行时发出事件,导致流阅读器解析并发出data事件。

我正在使用mochachai(使用chai-http)和sinon.spy来测试调用REST API的类接收响应的特定方案然后在响应处理程序中向其他事件侦听器发出“data”事件。

我已经阅读了很多关于使用带有Promise的chai-http来测试带有assert和expect的响应。为此,我尝试使用相同的模式来测试数据事件,但即使使用Promises,在完成Promise并且测试用例完成之后,才会触发sinon.spy侦听器。

关于测试案例......

第一次尝试 - 使用sinon.spy作为回调

it('should emit a "data" event when one record is POSTed and parsed', function() {
  let spy = sinon.spy();
  let reader = new Reader(sync_query);
  reader.on('data', spy);
  return chai.request(SYNC_URI)
    .post('/db/_bulk_docs')
    .set("Content-type", "application/json")
    .send({ "docs": [{"user": "tempura"}, {"user": "shrimp"}] })
    .then(function(response){
      expect(response.body).to.have.lengthOf(2);
      sinon.assert.calledOnce(spy);  
      // Executes too soon. I can see the event in another listener's logs. 
      // I'd like the test to run until the spy fires or a timeout occurs.
    })
    .catch(function(error) {
      throw error;
    });
    // EXITS BEFORE EVENTS are triggered?
});

编辑1 - 使用标准回调

it('should emit a "data" event when one record is POSTed and parsed', function() {
  let reader = new CouchReader(sync_query);
  // This works perfectly to catch when the event is fired but...
  reader.on('data', function(evt) {
    try {
      assert.isOk(evt);
      done();
    } catch (error) {
      done(error);
    }
  });
  chai.request(SYNC_GATEWAY_URI)
    .post('/db/_bulk_docs')
    .set("Content-type", "application/json")
    .send({ "docs": [{"user": "toszter"}, {"user": "bartacus"}] })
    .then(function(response){
      // ...the next expect doesn't get caught when thrown.
      // Can't return chai.request as a promise b/c of the callback.
      expect(response.body).to.have.lengthOf(3);
    })
    .catch(function(error) {
      throw error;
    });
  this.timeout(4000);
});

我想知道......

  1. 我应该将下面的代码转换为延迟的promise并将整个块返回给mocha,因为chai.request中的断言与回调中的断言正交,但两者都会影响测试的结果,或者..
  2. 我应该把它分成两个独立的测试单独测试单元...一个用于回调事件发出,另一个用于响应/db/_bulk_docs请求?
  3. 您的投票可能是选项2,是吗?

    我尝试过done(正确吗?),然后setImmediate(),现在正在考虑process.nextTick()而使用非Promise版本,但首先,我作为其他有更多使用经验的人摩卡(等)测试类似的场景:

    1. 我们如何阻止测试用例完成,直到某个事件被听众捕获或者在30秒沉默后超时?
    2. 我应该使用vanilla NodeJS request模块吗?
    3. 请原谅我,如果那里有重复,但在我的搜索中,我找不到一个......

1 个答案:

答案 0 :(得分:0)

这可能不是最好的答案,但我已经找到了解决方案。我的OP是集成测试的问题,不仅仅是一个单元。我正在尝试测试(这些单位):

  1. 对DB Gateway Server的API请求可以使用输入进行响应。
  2. Reader Class API监视器“检测到”DB Gateway Server活动。
  3. Reader Class发出data事件。
  4. data事件与我发送给API请求的输入一起打包。
  5. 这是一个太多来放一个测试用例和一个宝贵的教训。

    相反,我只使用每个需要的代码独立测试每个案例。

    describe.only('#message', function() {
      it('should emit a "bdata" event when message is called.', function() {
        let spy = sinon.spy();
        let reader = new Reader(sync_query);
        reader.on('data', spy);
        reader.message({obj: {last_seq: 1}});
        sinon.assert.calledOnce(spy); // Hooray, it works!
      });
    });
    

    但是,如果我真的在一次尖锐的斧头之后进行端到端的集成测试,那么为什么不呢?正如他们在Pushkar所说的那样。

    describe('#message event', function() {
      it('should emit a "data" event when Server saves data via Gateway APIs', function(done) {
        let reader = new CouchReader(sync_query);
        reader.on('data', function(evt) { // <-- I could make this a spy()
          try {
            assert.isOk(evt);
            // assert the event payload here
            done();
          } catch (error) {
            done(error);
          }
        });
        chai.request(SYNC_GATEWAY_URI)
          .post('/db/_bulk_docs')
          .set("Content-type", "application/json")
          .send({ "docs": [{"user": "toszter"}, {"user": "bartacus"}] })
          .catch(function(error) {
            throw error;
          });
        this.timeout(4000);
      });
    });
    

    ...在这种情况下,如果它超时,那么我已经丢失了我的球拍并开始了新的任务。