2014-10-30 114 views
5

我有一些我想用測試覆蓋的緊密耦合的遺留代碼。有時候確保一個模擬出來的方法在另一個之前被調用是很重要的。一個簡單的例子:如何測試一個函數在另一個函數之前被調用

function PageManager(page) { 
    this.page = page; 
} 
PageManager.prototype.openSettings = function(){ 
    this.page.open(); 
    this.page.setTitle("Settings"); 
}; 

在測試中我可以檢查兩個open()setTitle()被稱爲:

describe("PageManager.openSettings()", function() { 
    beforeEach(function() { 
     this.page = jasmine.createSpyObj("MockPage", ["open", "setTitle"]); 
     this.manager = new PageManager(this.page); 
     this.manager.openSettings(); 
    }); 

    it("opens page", function() { 
     expect(this.page.open).toHaveBeenCalledWith(); 
    }); 

    it("sets page title to 'Settings'", function() { 
     expect(this.page.setTitle).toHaveBeenCalledWith("Settings"); 
    }); 
}); 

setTitle()後,才第一次調用open()工作。我想檢查第一個page.open()被調用,然後是setTitle()。我想寫的東西是這樣的:

it("opens page before setting title", function() { 
    expect(this.page.open).toHaveBeenCalledBefore(this.page.setTitle); 
}); 

但茉莉似乎並不具有這樣的功能內置

我砍了這樣的事情:

beforeEach(function() { 
    this.page = jasmine.createSpyObj("MockPage", ["open", "setTitle"]); 
    this.manager = new PageManager(this.page); 

    // track the order of methods called 
    this.calls = []; 
    this.page.open.and.callFake(function() { 
     this.calls.push("open"); 
    }.bind(this)); 
    this.page.setTitle.and.callFake(function() { 
     this.calls.push("setTitle"); 
    }.bind(this)); 

    this.manager.openSettings(); 
}); 

it("opens page before setting title", function() { 
    expect(this.calls).toEqual(["open", "setTitle"]); 
}); 

這作品,但我想知道是否有一些簡單的方法來實現這一點。或者一些很好的方式來概括這個,所以我不需要在其他測試中複製此代碼。

PS。當然,正確的方法是重構代碼以消除這種時間耦合。儘管如此,它可能並不總是可能的。當與第三方庫連接時。無論如何,我想首先用測試覆蓋現有代碼,儘可能少地修改它,然後再深入研究重構。

+0

除了'open'已被調用之外,你是否可以斷言?像一些DOM節點更改或其他「全局」數據? – 2014-10-30 11:03:34

+0

不是。關鍵是我在嘲笑它 - 我不想讓實際的「open」被調用,特別是因爲它可能影響到某個全局狀態。 – 2014-10-30 12:50:58

+0

[有沒有辦法用Jasmine驗證間諜執行的順序?](https://stackoverflow.com/questions/20055781/is-there-a-way-to-verify-the-order-of -spy-executions-with-jasmine) – carpeliam 2018-01-03 01:45:24

回答

3

試試這個:

it("setTitle is invoked after open", function() { 
    var orderCop = jasmine.createSpy('orderCop'); 
    this.page.open = jasmine.createSpy('openSpy').and.callFake(function() { 
     orderCop('fisrtInvoke'); 
    }); 

    this.page.setTitle = jasmine.createSpy('setTitleSpy').and.callFake(function() { 
     orderCop('secondInvoke'); 
    }); 

    this.manager.openSettings(); 

    expect(orderCop.calls.count()).toBe(2); 
    expect(orderCop.calls.first().args[0]).toBe('firstInvoke'); 
    expect(orderCop.calls.mostRecent().args[0]).toBe('secondInvoke'); 
} 
0

通過對間諜使用.calls.first().calls.mostRecent()方法檢查特定呼叫。

+0

這隻在比較一個方法的調用時有幫助 - 無論是「foo()」是否首先用參數「a」或「b」調用 - 但它決定了在方法bar()之前是否調用了'foo()'方法。 – 2014-10-30 12:58:09

0

基本上做了同樣的事情。我對此感到有信心,因爲我用完全同步的實現來嘲笑函數行爲。

it 'should invoke an options pre-mixing hook before a mixin pre-mixing hook', -> 
    call_sequence = [] 

    mix_opts = {premixing_hook: -> call_sequence.push 1} 
    @mixin.premixing_hook = -> call_sequence.push 2 

    spyOn(mix_opts, 'premixing_hook').and.callThrough() 
    spyOn(@mixin, 'premixing_hook').and.callThrough() 

    class Example 
    Example.mixinto_proto @mixin, mix_opts, ['arg1', 'arg2'] 

    expect(mix_opts.premixing_hook).toHaveBeenCalledWith(['arg1', 'arg2']) 
    expect(@mixin.premixing_hook).toHaveBeenCalledWith(['arg1', 'arg2']) 
    expect(call_sequence).toEqual [1, 2] 
1

我想寫的東西是這樣的:

it("opens page before setting title", function() { 
    expect(this.page.open).toHaveBeenCalledBefore(this.page.setTitle); 
}); 

但茉莉似乎並不具備這樣的功能內置

看起來像茉莉花人看到這個帖子,因爲this functionality exists。我不確定它的存在時間 - 他們的所有API文檔都回到2.6提到它,儘管他們的存檔舊式文檔沒有提及它。

toHaveBeenCalledBefore(expected
expect實際值(Spy)之前另一Spy已被調用。

參數:

Name  Type Description 
expected Spy  Spy that should have been called after the actual Spy. 

故障您的例子看起來像Expected spy open to have been called before spy setTitle

0

最近我已經制定了茉莉花間諜的替代品,稱爲strict-spies,它解決了在許多其他這樣的問題:

describe("PageManager.openSettings()", function() { 
    beforeEach(function() { 
     this.spies = new StrictSpies(); 
     this.page = this.spies.createObj("MockPage", ["open", "setTitle"]); 

     this.manager = new PageManager(this.page); 
     this.manager.openSettings(); 
    }); 

    it("opens page and sets title to 'Settings'", function() { 
     expect(this.spies).toHaveCalls([ 
      ["open"], 
      ["setTitle", "Settings"], 
     ]); 
    }); 
}); 
1

對於預期已經作出了第一個電話第二個呼叫創建一個假的函數

it("opens page before setting title", function() { 

    // When page.setTitle is called, ensure that page.open has already been called 
    this.page.setTitle.and.callFake(function() { 
     expect(this.page.open).toHaveBeenCalled(); 
    }) 

    this.manager.openSettings(); 
}); 
相關問題