如何将Kafka pub-sub语义转换为NodeJS中单元测试的peakNext promise语义

时间:2016-12-13 13:38:28

标签: node.js apache-kafka

在对我的NodeJS应用程序进行单元测试时,我正在尝试创建一个简单的帮助器类,它将Kafka pub-sub语义转换为适合单元测试的更简单的API。

我的想法是能够像这样编写mocha unittest:

        const testSubscriber = kafkaTestHelper.getTestSubscriber({topic:'test'});
        return someKafkaProducer.sendAsync({topic: 'test', message: randomWord})
          .then(() =>
            testSubscriber.next()
          ).then(msg => {
            msg.should.equal(randomWord);
          });

当然我还会添加辅助方法,例如

testSubscriber.nextUntil(someFilter)

这是受AKKA.NET TestKit的启发,它有类似的方法。

我有两个问题:

  1. 这是一种合理的方法还是基于NodeJS中的Kafka流处理有一些更简洁的单元测试应用逻辑方法?

  2. 任何人都可以发布编码示例,说明如何让testSubscriber按照我的意图工作吗?

1 个答案:

答案 0 :(得分:0)

这可能不是最优雅的解决方案,但它似乎有效,至少对我的初步测试而言。诀窍是创建一个不断增长的Promise列表,解析器函数通过引用保存在名为“resolvers”的数组中。然后,当有消息进入时,将使用该消息调用解析程序。通过这种方式,我可以将promises返回给任何调用next()的unittest,如果消息已经传递或者将来会传递,它将透明地工作。

我仍然觉得我在这里重新发明轮子,所以任何评论仍然会非常感激。

    function TestSubscriber(consumer, initialMessageFilter) {
      this.consumer = consumer;
      let promiseBuffer = [];
      let resolvers = [];
      let resolveCounter = 0;
      let isStarted = false;
      const ensurePromiseBuffer = function() {
        if (promiseBuffer.length === 0 || resolveCounter >= resolvers.length) {
          const newPromise = new Promise(function(resolve, reject) {
            resolvers.push(resolve);
          });
          promiseBuffer.push(newPromise);
        }
      }
      const that = this;
      this.consumer.on('message', function(message) {
        if (!isStarted) {
          //Determine if we should start now.
          isStarted = initialMessageFilter === undefined || initialMessageFilter(message);
        }
        if (isStarted) {
          ensurePromiseBuffer();
          const resolver = resolvers[resolveCounter];
          resolver(message);
          resolveCounter++;
          that.consumer.commit(function(err, data) {
            if (err) {
              //Just log any errors here as we are running inside a unittest
              log.warn(err)
            }
          })
        }
      });
      this.next = function() {
        ensurePromiseBuffer();
        return promiseBuffer.shift();
      };
    }

    const cache = {};

    module.exports = {
      getTestSubscriber: function({topic}, initialMessageFilter) {
        if (!cache[topic]) {
          const consumer = kafka.getConsumer({topic, groupId: GROUP_ID});
          cache[topic] = new TestSubscriber(consumer, initialMessageFilter);
        }
        return cache[topic];
      }
    }