2016-03-29 67 views
6

讓我們想象一下,我有以下方法下進行試驗:如何避免單元測試中的Thread.sleep?

@Autowired 
private RoutingService routingservice; 

public void methodToBeTested() { 
    Object objectToRoute = initializeObjectToRoute(); 
    if (someConditions) { 
     routingService.routeInOneWay(objectToRoute); 
    } else { 
     routingService.routeInAnotherWay(objectToRoute); 
    } 
} 

在這種情況下RoutingService在單獨的線程中運行,因此它的構造函數中,我們有以下幾點:

Thread thread = new Thread(this); 
thread.setDaemon(true); 
thread.start(); 

問題是RoutingService改變了objectToRoute的狀態,這正是我想要檢查的內容,但是這不會立即發生,因此測試失敗。但是,如果我添加Thread.sleep()那麼它可以工作,但這是不正確的做法,因爲我知道。

在這種情況下,我該如何避免Thread.sleep()

+0

在單元測試中使用'Thread.sleep'是不錯的做法,因爲您所做的只是模仿時間流逝,這對於某些單元測試是必需的。人們說使用Thread.sleep是一個不好的做法的原因是因爲它有時被用來解決競爭條件。 你只在測試或源代碼中使用'Thread.sleep'嗎? –

+0

當你測試線程代碼時,你如何確保你的單元測試不是片狀的?他們總是以確定性的方式執行。我認爲嘲笑服務類是一個更好的選擇 –

+0

我只在測試中使用睡眠,但發現了很多地方人們提到,一般來說睡眠在單元測試中不是很好。例如,SonarLint插件也抱怨說它違規並給出以下描述:「在測試中使用Thread.sleep通常是一個糟糕的主意,它會產生脆弱的測試,根據環境可能會無法預料地失敗(」Passes on我的機器!「)或加載。」 – Rufi

回答

4

如果你正在測試methodToBeTested,你應該簡單地模擬routingservice。您不應該測試methodToBeTested所調用的任何方法。但是,這聽起來像你想測試RoutingService(你說「問題是RoutingService改變了objectToRoute的狀態,這正是我想檢查的)」。要測試RoutingService方法,您應該爲這些方法編寫單獨的單元測試。

+0

是的,這可能是一種方式,但是,我不能說我喜歡它。很可能我的測試從單元測試轉移到集成測試。 RoutingService已經過測試,但在這種情況下,我想驗證在某些情況下路由已完成,但可能需要一些時間。當然,我可以模擬RoutingService並驗證具體的方法是否被調用,但是我不會介紹狀態更改。 – Rufi

+0

是的,我想說如果你想這樣做,它會成爲一個集成測試,不應該用正常的單元測試集運行。單元測試應該快速且一致地完成,因此開發人員可以在檢查任何代碼之前運行它們。有一套單獨的集成測試可以定期運行(例如通過Jenkins) – forgivenson

0

您可以模擬objectToRoute來設置CompletableFuture的值,然後在您的斷言中調用get。這將一直等到數值被設置後再繼續。然後設置超時@Test(timeout=5000)以防從未設置該值。

這樣做的好處是,測試不會等待超過必要的時間,並且由於時間太短而難以失敗,因爲您可以使超時比正常情況大得多。

0

這取決於。正如本格林在評論中所說,睡眠在測試中是危險的,因爲它可以隱藏競爭條件。 知道整個設計是否包含這樣的競爭條件,其中服務可以在路線準備好之前使用。它的確如此,你應該在代碼中修正它,例如通過測試準備好的條件,並在測試類中對其進行相同的測試。

如果你知道它不可能發生,你應該在你的測試類的主代碼中記錄它。那將是一個完美的睡眠理由。

(我認爲這是一個集成測試 - 單元測試嘲笑應該足夠爲你在其他的答案說的)

0

而是避免Thread.sleep()方法中,你可以通過值零Junit測試用例。

相關問題