2012-02-02 69 views
7

如果我有一個測試對象使用定時器來定時執行一些操作,那麼測試它的好方法是什麼?是否使用Thread.Sleep測試了定時間隔的操作?

一個method是將定時器包裝在一個接口中,並將其作爲依賴注入。

但是,我想避免創建另一個抽象。看來我可以通過注入更新間隔而不是定時器來避免這種情況。然後在我的測試中(假設採用AAA風格的測試),我在Act之後和認定之後放了一個Thread.Sleep,使用非常小的時間值,因此測試不需要很長時間就可以運行。

這是一個壞主意嗎?我知道它可能並不完全遵循TDD的原則,但是似乎必須有一條線路,讓您停止在合同中注入任何東西並注入它。

+3

」必須有一條線,在那裏你停止用合同注入所有東西並注入它「 - 異端,我說;) – 2012-02-02 22:53:27

+1

Windows中線程的調度不是確定性的,所以做這樣的事情可能會使你的測試失敗隨機。 – svick 2012-02-03 01:53:10

+0

@svick我沒有真的想檢查任何有關線程調度。只要我的計時器成功,就會在預期的時間內+一段寬限期內發生函數調用。像這樣的情況會不會受到這些問題的影響? – 2012-02-03 14:54:47

回答

5

如果您的睡眠量在測試中沒有任何意義,並且您可以將我設置爲1毫秒,那麼在測試中簡單地休眠1毫秒應該沒問題。但是,如果您想要測試具有超時的複雜計時行爲以及在特定時間點採取的特定操作,則可以快速抽象出時間概念並將其注入爲依賴項。然後,您的測試可以在虛擬時間內運行,並且即使代碼以實時通過的方式運行,也可以毫不拖延地執行。

一個簡單的方法來虛擬化的時間是用這樣的:

interface ITimeService { 

    DateTime Now { get; } 

    void Sleep(TimeSpan delay); 

} 

class TimeService : ITimeService { 

    public DateTime Now { get { return DateTime.UtcNow; } } 

    public void Sleep(TimeSpan delay) { Thread.Sleep(delay); } 

} 

class TimeServiceStub : ITimeService { 

    DateTime now; 

    public TimeServiceStub() { 
    this.now = DateTime.UtcNow; 
    } 

    public DateTime Now { get { return this.now; } } 

    public void Sleep(TimeSpan delay) { 
    this.now += delay; 
    } 

} 

你將不得不如果你需要像計時器射擊等

2

扶養注入更具反應性的行爲來擴展這個想法完全避免你的生產代碼中有任何「測試」代碼的方法(比如設置單元測試的時間間隔)。

但是,在這種情況下,我會使用設置的間隔代碼,但在單元測試和生產中都使用它。生產將其設置爲任何值,單元測試將其設置爲非常小的值(10ms?)。那麼在生產中你將不會有任何死代碼。

如果你設置了間隔,我不明白你爲什麼需要Thread.Sleep?只要你的單元測試阻止,直到你從主題獲得事件(或不斷輪詢主題)。無論你使用什麼方法。 「

+0

我不太確定如何在沒有'Thread.Sleep'的情況下編寫代碼...我之前使用過一個'AutoResetEvent'來測試事情,但我不知道如何使用模擬框架來做到這一點。任何例子?代碼示例可能會幫助我更好地理解您的意思。 – 2012-02-03 14:45:48

相關問題