[英]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.