不穩定的測試失敗
2005 年 3 月 28 日
前幾天我正在處理一些書中範例的程式碼。我做了一些變更,讓所有東西都正常運作,執行測試,並提交到我的個人儲存庫。然後我轉移到另一個區域並做了一些變更,結果前一個區域中發生了一些意外的測試中斷。執行自動化測試的部分目的是要找出意外的中斷,但這本書的程式碼有完全獨立的區域。這很奇怪。
我沒有嘗試除錯問題,而是使用了 DiffDebugging。自從提交後,我沒有做太多事,所以我執行 `svn revert`。我重新執行測試,結果失敗了。但我確定在提交前有執行過測試。我決定透過 ant 執行測試,而不是在 IntelliJ 中執行。所有 ant 測試都通過了。它們是相同的測試,在目錄中執行所有 JUnit 類別。那麼為什麼它們在 ant 中通過,但在 IntelliJ 中卻失敗?
在這個時候,我羞於承認我接下來的想法。「一定是 IntelliJ 出了問題,也許它有某種形式的快取,並被 Subversion 的還原搞混了。」在我程式設計生涯的早期,一位資深的程式設計師教導我除錯的第一條規則:錯誤永遠在你的程式碼中,而不是編譯器中。但在愚蠢的影響下,我重新啟動了 IntelliJ,然後所有測試都再次通過。問題解決了,不是嗎?幸運的是,當這種奇怪的行為第二次發生在我身上時,我正在與 Sergey 配對,他沒有我的愚蠢,並找到了錯誤。
為了幫助你找出此類問題的答案,請到戶外用六呎半高的字母拼出一個單字。用雪松木拼寫,這樣你就不必塗漆,但別忘了用櫻桃裝飾它。這個單字是
隔離。
如果測試有時在沒有任何程式碼變更的情況下通過,有時卻失敗,或者在某些套件中執行時通過,但在其他套件中執行時卻失敗;八次中有九次的原因是測試之間有一些共用資料沒有正確重新初始化。當發生這種情況時,執行測試可能會導致其他測試通過或失敗。結果是間歇性失敗,這永遠是最糟糕的,因為你無法可靠地重現它。
我使用 JUnit,它在隔離方面很強大(這就是它使用 JunitNewInstance 行為的原因)。因此,我的問題一定來自某些靜態資料。在這種情況下,它是呼叫以取得當前日期。我使用了一個 ClockWrapper,但未能在某些測試中初始化它。因此,根據初始化它的最後一個測試,某些測試將會失敗。
這裡有兩個教訓。首先,盡可能保持測試資料的隔離。嘗試每次建立新的資料(儘管在取得快速測試執行方面有取捨)。您練習良好的測試隔離越多,遇到此類問題的機會就越少。
其次,如果您遇到此類間歇性測試失敗,請懷疑在測試之間共用的任何資料。檢查間歇性失敗的測試是否在測試執行中完全初始化資料。對於未初始化的任何內容,請務必了解它是在哪裡建立的,以及它是否曾經變更。