用茉莉拦截EventEmitters

Intercept EventEmitters with Jasmine

本文关键字:EventEmitters      更新时间:2023-09-26

我正在构建一个node.js模块,我也想用Jasmine测试它。

假设我的模块看起来与此类似:

var myModule = function (foo, bar) {
  // Begin a workflow
  var workflow = new (require('events').EventEmitter)();
  workflow.on('test', function () {
    var greet = greet();
    return greet;
  });
  workflow.emit('test');
};
function greet () {
  return "Hi!";
}
module.exports = {
  myModule: myModule
};

如何使用Jasmine针对我发出的所有事件测试我的模块?

类似这样的东西:

var myModule = require('../myModule.js');    
describe('My Module test', function () {
  it('should get greet value', function () {
    myModule.on('test', function () { // "test" as I wrote in myModule
      expect(myModule.greet).toHaveBeenCalled();
    });
  });
});

我使用proxyquire实现了这一点:https://github.com/thlorenz/proxyquire

在您的测试文件中:

var proxyquire =  require('proxyquire');
var mockEvents = {};
var myModule = proxyquire('../myModule.js', {
  events: mockEvents
});
describe('My Module test', function () {
  beforeEach(function() {
    mockEvents.EventEmitter = function () {};
    mockEvents.EventEmitter.prototype = {
      on: function () { },
      emit: function () { }
    };
    spyOn(mockEvents.EventEmitter.prototype, 'on');
    spyOn(mockEvents.EventEmitter.prototype, 'emit');
  });
  it('should get greet value', function () {
    myModule()
    expect(mockEvents.EventEmitter.prototype.on).toHaveBeenCalledWith('test');
    expect(mockEvents.EventEmitter.prototype.emit).toHaveBeenCalledWith('test');
  });
});

您也可以使用间谍作为模拟EventEmitter等。

主要问题是greet没有真正公开,因此在测试中无法访问。以下是一些处理方法:

  1. 将它添加到原型链中以使其可访问(这是我在下面所做的(。

  2. module.exports中显示函数。这可以封装在process.env.NODE_ENV !== production中以将其从生产中排除。

  3. 不公开它,而是测试事件发射器的功能和功能的影响(这可能不理想(。

为了实现你想要的,你可以对函数进行猴子补丁,测试它们是否被调用,并单独测试greet的结果:

MyModule.js

var EventEmitter = require('events').EventEmitter;
var MyModule = function (foo, bar) {
  // Begin a workflow
  var workflow = new EventEmitter();
  workflow.on('test', function () {
    return this.greet();
  }.bind(this));
  workflow.emit('test');
};
MyModule.prototype.greet = function () {
  return "Hi!";
};
module.exports = MyModule;

MyModule tests.js

var EventEmitter = require('events').EventEmitter;
describe('MyModule', function () {
  it('emits an event upon construction', function () {
    // Monkey patch
    var originalEventEmitterOn = EventEmitter.prototype.on;
    EventEmitter.prototype.on = jasmine.createSpy('on');
    // Create module
    var MyModule = require('./MyModule');
    new MyModule();
    expect(EventEmitter.prototype.on).toHaveBeenCalled();
    // Reset
    EventEmitter.prototype.on = originalEventEmitterOn;
  });
  it('calls greet upon construction', function () {
    var MyModule = require('./MyModule');
    // Monkey patch
    var originalGreet = MyModule.prototype.greet
    MyModule.prototype.greet = jasmine.createSpy('greet');
    var myModule = new MyModule();
    expect(myModule.greet).toHaveBeenCalled();
    // Reset
    MyModule.prototype.greet = originalGreet;
  });
  it('returns "Hi!"', function () {
    var MyModule = require('./MyModule');
    var myModule = new MyModule();
    expect(myModule.greet()).toBe("Hi!");
  });
});