我有一个扩展EventEmitter的依赖类,我需要测试使用此依赖项的函数将如何根据它触发的事件做出反应。你如何存根EventEmitter类的函数?
依赖类
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;
受测试的相关模块
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
我使用Sinon来创建一个存根,但我还没有能够存储有效发出事件的类函数。我将我的测试建模为[Feature request] stub emits,但由于事件发射器依赖关系是一个类,因此必须进行一些修改。
测试
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...
});
});
即使正在调用存根函数,此方法实际上也不会发出事件。
答案 0 :(得分:0)
测试中的第13行,它调用dependentModule.myFunction()
然后它跳转到受测试的相关模块中的第5行
然后在受测试的从属模块的第19行中,它调用fooBar.doSomething()
然后它跳转到依赖类中的第12行,this.doingSomething
为假,因此它会发出startedDoingSomething
。
然后它跳转到Dependent Module Under Test中的第7行,它调用fooBar.removeAllListeners();
,这意味着在同一文件的第34行注册的事件处理程序也被删除。
这是有意的吗?
现在假设第7行中的fooBar.removeAllListeners
注释掉了受管模块。
在测试中的第13行之后,它会调用FooBar.prototype.pause
,然后调用FooBar.prototype.emit('alreadyDoingSomething');
问题是,当调用FooBar.prototype.emit
时,上下文中的this
不等于“受测试的相关模块”中第2行中声明的fooBar
。 (它等于FooBar.prototype
)
因此FooBar.prototype.emit('alreadyDoingSomething');
不会触发在受测试的从属模块中第12行定义的事件处理程序。
我们需要找到一种方法来调用fooBar.emit('alreadyDoingSomething')
。
但这是不可能的,因为永远不会导出fooBar
,除非使用了rewire这样的库。
现在假设我们将exports.fooBar = fooBar;
添加到受测试的从属模块的末尾。
我们还将Test中的第9行更改为this.emit('alreadyDoingSomething')
这很重要,因为我们需要在调用emit时需要作为实例的上下文,在我们的例子fooBar
中。
现在在Test中,当调用dependentModule.fooBar.pause()
时,会触发已经做过的东西。
现在您应该在控制台中看到Already Doing Something
。