【问题标题】:Unit testing an event which is not bound by event emitter对不受事件发射器绑定的事件进行单元测试
【发布时间】:2016-05-24 02:58:25
【问题描述】:

我有以下代码。

  private client: any;

  this.client = mqtt.connect(url, mqttOptions);

  this.client.on('message', (topic: string, message: string) => {
   console.log('came inside onMessage');
    let ksiotMessage: KSIOTMessage;
    let receivedTopic: KSIOTTopic;
    receivedTopic = getValue(topic);
    ksiotMessage = {
      ksiotTopic: receivedTopic,
      payload: message
    };
    messageReceivedCallBack.onMessageReceived(ksiotMessage);
  });

在这里,当 mqtt 客户端发出消息事件时,会触发一个匿名函数。我无法控制它,这意味着它不是我,将它绑定到事件发射器。此外,我无法添加计时器并等待此事件触发,因为我使用 sinon 模拟了客户端的连接性。所以没有真正的联系。那么如何手动发出此消息事件并查看 messageReceivedCallBack 的 onMessageReceived 是否被调用?我是 Javascript 单元测试的新手。目前我正在使用 mocha 和 sinon 来满足我的单元测试需求。

请指教。

【问题讨论】:

  • 您的测试代码需要访问this.clientmessageReceivedCallBack。是这样吗?
  • this.client 被分配了一个来自“mqtt.connect”行的值。因此,为此我要返回我自己的存根。我需要知道如何触发这个连接事件,以便测试里面的代码。由于我已经存根连接方法,“消息”事件不会自动触发。我需要手动触发它。我不知道怎么做:(

标签: javascript typescript mocha.js sinon chai


【解决方案1】:

首先声明:我不了解 TypeScript,也不了解您的应用程序的内部结构,因此以下内容可能无法开箱即用。但是,它可能会为您提供一些关于如何实施此类测试的想法。

我抽象了你的客户端代码(需要测试的代码):

// mqtt-module.js
const mqtt = require('mqtt');
const messageReceivedCallBack = require('./callbacks');

// This mimics what your code does. Instead of a class I just make it a
// simple function.
module.exports = {
 setup() {
    let client = mqtt.connect();
    client.on('message', (topic, message) => {
      // We want to test this.
      messageReceivedCallBack.onMessageReceived(message);
    });
  }
}

在您的代码中,不清楚messageReceivedCallBack 的来源。因为您必须能够从 Sinon 访问它,所以它应该位于可导入模块中(但是,这确实依赖于导入被缓存的事实,例如 require(),我不确定 TS 是否这样做)。

这是我使用的一个简单的模拟:

// callbacks.js
module.exports = {
  onMessageReceived(message) {}
};

最后,测试本身。它相当复杂,因为它需要做各种事情:

  • 创建一个EventEmitter 子类,用于将原来的MqttClient 替换为
  • 存根各种函数和回调
  • 设置测试环境

代码:

// test.js
const mqtt = require('mqtt');

// The modules mentioned above.
const mqttModule              = require('./mqtt-module');
const messageReceivedCallBack = require('./callbacks');

// Set up Sinon and Chai
const sinon = require('sinon');
const chai  = require('chai');
let expect  = chai.expect;
chai.use(require('sinon-chai'));

// Create a fake client for testing purposes.
const EventEmitter = require('events').EventEmitter;
class Client extends EventEmitter {}

// The test case.
describe('my test case', () => {
  var mockClient;

  beforeEach(() => {
    mockClient = new Client();
    // mqtt.connect() returns a fake client instance, with
    // just enough logic to allow events to be emitted and
    // received.
    sinon.stub(mqtt, 'connect').returns(mockClient);

    // Call the setup of our MQTT class (this will likely be
    // entirely different in your case, but the idea is that
    // it gets called _after_ `mqtt.connect()` gets stubbed.
    mqttModule.setup();
  });

  afterEach(() => {
    // Restore the original.
    mqtt.connect.restore();
  });

  it('should call messageReceivedCallBack.onMessageReceived', () => {
    // The message that we're going to pass.
    let message = 'this is a test message';

    // We want to stub messageReceivedCallBack.onMessageReceived()
    sinon.stub(messageReceivedCallBack, 'onMessageReceived');

    // Emit a `message` event on our mock client, which will trigger
    // the `client.on('message', ...)` in your MQTT class.
    mockClient.emit('message', 'topic', message);

    // Test if the stub was called with the proper argument.
    expect(messageReceivedCallBack.onMessageReceived).to.be.calledWith(message);

    // Restore to the original function.
    messageReceivedCallBack.onMessageReceived.restore();
  });

});

【讨论】:

  • 很棒的解决方案伙伴! :)
【解决方案2】:
export class MqttClientMock extends events.EventEmitter {
  subscribe = sinon.stub()
  publish = sinon.stub()
  unsubscribe = sinon.stub()
}

sandbox.stub(mqtt, 'connect').returns(new MqttClientMock() as undefined as MqttClient)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-09-12
    • 1970-01-01
    相关资源
    最近更新 更多