Javascript 存根ES6 EventEmitter类函数
我有一个扩展EventEmitter的依赖项类,我需要测试使用此依赖项的函数如何根据它触发的事件做出反应。如何存根EventEmitter类的函数 依赖类Javascript 存根ES6 EventEmitter类函数,javascript,node.js,unit-testing,sinon,stubbing,Javascript,Node.js,Unit Testing,Sinon,Stubbing,我有一个扩展EventEmitter的依赖项类,我需要测试使用此依赖项的函数如何根据它触发的事件做出反应。如何存根EventEmitter类的函数 依赖类 const EventEmitter = require('events'); class FooBar extends EventEmitter { constructor() { super(); this.doingSomething = false; } doSomething() { if
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
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...
});
});
我使用Sinon来创建存根,但我无法有效地存根发出事件的类函数。我对的测试进行了建模,但由于要存根的事件发射器依赖项是一个类,因此必须进行一些修改
测试
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
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...
});
});
即使正在调用存根函数,这种方法实际上也不会发出事件。在测试的第13行,它调用
dependentModule.myFunction()
然后跳转到被测从属模块中的第5行
然后在被测依赖模块的第19行中,它调用fooBar.doSomething()
然后它跳转到依赖类的第12行,这里有这个。doingSomething
是false,所以它发出startedDoingSomething
然后它跳转到被测依赖模块的第7行,调用fooBar.removeAllListeners()代码>,这意味着在同一文件的第34行注册的事件处理程序也将被删除
这是真迹吗
现在假设第7行中的fooBar.removeAllListeners
被测试的依赖模块被注释掉
在测试的第13行之后,它调用FooBar.prototype.pause
,后者依次调用FooBar.prototype.emit('alreadyDoingSomething')代码>
问题是,当调用FooBar.prototype.emit
时,上下文中的此
不等于测试中的依赖模块第2行中声明的FooBar
。(它等于FooBar.prototype
)
所以FooBar.prototype.emit('alreadyDoingSomething')代码>不会触发测试中的依赖模块第12行中定义的事件处理程序
我们需要找到一种方法来调用fooBar.emit('alreadyDoingSomething')
但这是不可能的,因为永远不会导出fooBar
,除非使用类似的库
现在假设我们添加exports.fooBar=fooBar代码>至受测从属模块的末尾
我们还将测试中的第9行更改为this.emit('alreadyDoingSomething')
,这很重要,因为调用emit时需要上下文,在我们的例子中,fooBar
现在在测试中,当调用dependentModule.fooBar.pause()
时,会触发一个alreadyDoingSomething
现在您应该看到已经在控制台中执行了一些操作。是-第7行的removeAllListeners()调用是有意的,因为它可以防止myFunction在发出单个事件后挂起。在这种特殊情况下,我只关心发出的第一个事件,但需要处理所有情况。您建议的导出修复确实有效——即使没有对removeAllListeners()调用进行注释——但不幸的是,仅使用构造函数而不是类的确切实例无法实现这一点。