简体   繁体   English

存根ES6 EventEmitter类函数

[英]Stub a ES6 EventEmitter class function

I have a dependency class that extends EventEmitter and I need to test how a function that uses this dependency will react based on the events that it fires. 我有一个扩展EventEmitter的依赖项类,我需要测试使用此依赖项的函数如何根据触发的事件做出反应。 How do you stub a function of a EventEmitter class? 如何对EventEmitter类的函数进行存根?

Dependency Class 依赖类

const EventEmitter = require('events');

class FooBar extends EventEmitter {

  constructor() {
    super();

    this.doingSomething = false;
  }

  doSomething() {
    if (this.doingSomething === false) {
      this.doingSomething = true;
      this.emit('startedDoingSomething');
    }
    else {
      this.emit('alreadyDoingSomething');
    }
  }
}

module.exports = FooBar;

Dependent Module Under Test 被测模块

let Foobar = require('FooBar');
let fooBar = new FooBar();

exports.myFunction = () => {
  // Set up listeners
  fooBar.once('startedDoingSomething', () => {
    fooBar.removeAllListeners();
    // Some functionality
    console.log('Started Doing Something');
  });

  fooBar.once('alreadyDoingSomething', () => {
    fooBar.removeAllListeners();
    // Some functionality
    console.log('Already Doing Something');
  });

  // Call the event-emitting function
  fooBar.doSomething();
};

// Other functions that use fooBar

I'm using Sinon in order to create a stub, but I haven't been able to stub the class functions that emit events effectively. 我正在使用Sinon来创建存根,但是我无法对有效发出事件的类函数进行存根。 I modeled my test off of [Feature request] stub emits but had to make some modifications since the event emitter dependency being stubbed is a class. 我根据[Feature request]存根发出的内容对测试进行了建模,但是由于被存根的事件发射器依赖项是一个类,因此不得不进行一些修改。

Test 测试

let chai = require('chai');
let sinon = require('sinon');
let FooBar = require('FooBar');
let dependentModule = require('./dependentModule');

describe('Dependent Module', () => {
  it('alreadyDoingSomething', () => {
    sinon.stub(FooBar.prototype, 'pause', () => {
      FooBar.prototype.emit('alreadyDoingSomething');
    });

    // Assertion statements here
    expect(dependentModule.myFunction()).to...
  });
});

This approach does not actually emit an event even though the stub function is being called. 即使正在调用存根函数,该方法实际上也不会发出事件。

Line 13 in Test, it calls dependentModule.myFunction() 测试中的第13行,它调用dependentModule.myFunction()

Then it jumps to line 5 in Dependent Module Under Test 然后它跳到被测从属模块的第5行

Then in line 19 in Dependent Module Under Test, it calls fooBar.doSomething() 然后在受测从属模块的第19行中,它调用fooBar.doSomething()

Then it jumps to line 12 in Dependency Class, there this.doingSomething is false, so it emits startedDoingSomething . 然后跳到Dependency Class中的第12行,那里this.doingSomething为false,因此它发出了startedDoingSomething

Then it jumps to line 7 in Dependent Module Under Test, it calls fooBar.removeAllListeners(); 然后,它跳到“受测模块”中的第7行,它调用fooBar.removeAllListeners(); , which means the event handler registered at line 34 of the same file is also removed. ,这意味着在同一文件的第34行注册的事件处理程序也将被删除。

Is this inteded? 这是真的吗?

Now assume fooBar.removeAllListeners in line 7 Dependent Module Under Test is commented out. 现在,假设第7行“受测模块”中的fooBar.removeAllListeners已被注释掉。

And after line 13 in Test, it calls FooBar.prototype.pause which in turn calls FooBar.prototype.emit('alreadyDoingSomething'); 然后在Test的第13行之后,它调用FooBar.prototype.pause ,然后依次调用FooBar.prototype.emit('alreadyDoingSomething');

The problem is that when FooBar.prototype.emit is called, this in the context is not equal to fooBar declared in line 2 in Dependent Module Under Test. 问题在于,当FooBar.prototype.emit时, this在上下文中不等于在受测模块中的第2行中声明的fooBar (It is equal to FooBar.prototype ) (等于FooBar.prototype

So FooBar.prototype.emit('alreadyDoingSomething'); 所以FooBar.prototype.emit('alreadyDoingSomething'); won't trigger event handler defined in line 12 in Dependent Module Under Test. 不会触发在受测模块中第12行中定义的事件处理程序。

We will need to find a way to call fooBar.emit('alreadyDoingSomething') . 我们将需要找到一种方法来调用fooBar.emit('alreadyDoingSomething')

But that's impossible, because fooBar is never exported, unless some library like rewire is used. 但这是不可能的,因为除非使用诸如rewire之类的库,否则永远不会导出fooBar

Now assume we add exports.fooBar = fooBar; 现在假设我们添加了exports.fooBar = fooBar; to the end of Dependent Module Under Test. 到被测相关模块的末尾。

And we also change line 9 in Test to this.emit('alreadyDoingSomething') This is important, because we need the context when emit is called needs to be the instance, in our case fooBar . 并且我们还将Test中的第9行更改为this.emit('alreadyDoingSomething')这很重要,因为我们需要在调用this.emit('alreadyDoingSomething')时需要上下文作为实例,在我们的例子中是fooBar

And now in Test, when dependentModule.fooBar.pause() is called, that triggers a alreadyDoingSomething. 现在在测试中,当调用dependentModule.fooBar.pause()时,将触发一个“已经开始做事”。

Now you should see Already Doing Something in your console. 现在,您应该在控制台中看到Already Doing Something

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM