2017-02-18 44 views
0

我有一個擴展EventEmitter的依賴類,我需要測試一個使用此依賴性的函數如何基於它觸發的事件作出反應。你如何存儲一個EventEmitter類的函數?存根ES6 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 

,以創建一個存根我使用興農,但我一直沒能存根可以有效地發射事件的類函數。我將我的測試建模爲[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

在試驗線13時,它調用dependentModule.myFunction()

然後跳躍相關模塊到線5在測試

然後在依賴被測模塊線19時,它調用fooBar.doSomething()

然後,它跳轉到依賴類中的第12行,那麼this.doingSomething爲false,因此它會發出startedDoingSomething

然後,它跳轉到受測試的從屬模塊中的第7行,它調用fooBar.removeAllListeners();,這意味着在同一個文件的第34行註冊的事件處理程序也會被刪除。

這是有意圖嗎?

現在假設fooBar.removeAllListeners在第7行中依賴測試的模塊被註釋掉。

而在測試線路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;添加到受測試從屬模塊的末尾。

而且我們還將測試中的第9行更改爲this.emit('alreadyDoingSomething')這很重要,因爲我們需要在調用emit時需要的上下文,在我們的例子中爲fooBar

現在在測試中,調用dependentModule.fooBar.pause()時,會觸發alreadyDoingSomething。

現在您應該在您的控制檯中看到Already Doing Something

+0

是的 - 第7行的removeAllListeners()調用是有意的,因爲它可以防止發生單個事件後myFunction掛起。在這個特殊情況下,我只關心已發出的第一個事件,但需要處理所有情況。 您建議的導出修復功能可以工作 - 即使沒有對removeAllListeners()調用進行註釋 - 但不幸的是,沒有辦法使這個工作只用構造函數而不是類的確切實例。 –