撰寫 Fuchsia 測試時,建議您確保熟悉用於編寫測試的測試原則和測試範圍。
測試的理想屬性
如果下列屬性不會與測試的其他目標衝突,通常建議具備。
- 隔離:測試應與測試範圍外的程式碼、系統及詳細資料區隔開來。不同的測試案例應彼此區隔。在 Fuchsia 中,我們會使用元件架構提供的隔離保證來區隔測試。隔離的測試結果是,測試可以同時或以不同順序執行,且結果相同。
- Hermetic:測試結果由測試內容定義。在 Fuuchsia 中,如果測試結果是由測試套件的內容所定義,就屬於封閉測試或整合測試。如果測試套件尚未變更,可能會假設其行為沒有變更,且仍在通過或仍失敗。這項屬性可用來選取要執行的測試,以驗證特定變更。如果沒有密封保證,下一個最佳替代方案就是執行所有測試,費用高昂。
- 可重現:重新執行同一項測試應會產生相同的結果。 隔離與密封有助於提升可重現性。測試範圍越大,可重現測試的難度就越難。
- 測試中程式碼的鄰近性:測試應聚焦於特定單元和測試,並控制不適合測試的項目。
- 具彈性:除非變更對程式碼用途至關重要,否則測試不應在測試變更的程式碼發生時變更。如果測試在程式碼的良性變更後繼續運作,可以保有更彈性。執行程式碼公用 API 或其他形式合約的測試,往往更具彈性。當您著重於測試行為,而非實作時,也會發生此情況。
- 易於疑難排解:測試失敗時,應產生可採取行動的明確錯誤來找出瑕疵。隔離錯誤或範圍較小的測試,通常在失敗時比較容易排解問題。
- 快速:測試通常是開發人員意見回饋循環的一部分。加快意見回饋循環的速度是更完善的意見回饋循環,可提高開發人員的工作效率。
- 可靠:測試失敗應表示測試中的程式碼確實有瑕疵。可靠的測試能夠在通過測試時更有信心,並減少產生的假失敗次數,增加維護成本。
- 彈性:執行測試的限制越少,執行時就越容易。如果可以的話,我們特別喜歡在 Fuchsia 上執行測試。
不理想的測試屬性
以下屬性通常不太容易出現。視情況而定,這些是出於測試目的而做出取捨的缺點 (整體來說會是淨陽性)。
- 不穩定:產生假失敗的測試,然後在重試後通過測試,因此表現不穩定。不穩定的測試較昂貴,且因重試而執行速度較慢,且可信度不足。
- 慢:測試花費較長時間,可建立效率較低的意見回饋循環,並降低開發人員的工作效率。測試範圍越大,執行速度通常越慢。
- 難以疑難排解:測試失敗且無法立即採取行動的測試,或沒有表示失敗的根本原因較難以進行疑難排解。開發人員需要查看測試失敗本身以外的地方,例如系統記錄或內部系統狀態,才能對測試失敗進行疑難排解。
- 變更偵測工具:如果測試與對功能無關的實作細節過於緊密,則當測試中的程式碼變更對外部觀察器的良性時,通常就會失敗。變更偵測工具測試的維護成本也比較高。
針對介面和合約進行測試
建議:使用公開 API,以及提供給受測試程式碼用戶端的其他介面和合約進行測試。這些測試更能有效應對良性變化。
不建議使用:請勿測試用戶端不重要的實作詳細資料。如果測試中的程式碼以正規方式變更,這類測試通常會損毀。
相關資源:
編寫可讀取的測試程式碼
編寫測試時請將可讀性納入考量,就像撰寫測試中的程式碼時一樣。
- 如果測試主體包含解讀測試所需的所有資訊,就表示測試已完成。
- 如果測試不含任何其他幹擾性資訊,則測試屬於「精簡內容」。
建議:編寫簡明扼要的測試案例。最好編寫更多的測試案例,每個測試案例都很小,聚焦於特定情況和疑慮。
不建議使用:請勿將多個情境合併為較少的測試案例,以產生較少測試案例的較短測試。
相關資源:
編寫可重現的確定性測試
測試應具有確定性,也就是說,每次執行相同程式碼修訂版本時都會產生相同的結果。如果不符,測試的維護費用可能會增加。
執行緒或時間相依程式碼、隨機號碼產生器 (RNG),以及跨元件通訊,都是非確定性的常見來源。
建議:運用下列提示編寫確定性測試:
- 針對時間相依測試,請使用假或模擬的時鐘來提供確定性。請查看
fuchsia_async::Executor::new_with_fake_time
和 fake-clock。 - 執行緒程式碼必須一律使用適當的同步基元,才能避免發生延遲。請盡可能採用單一執行緒測試。
- 請一律提供為 RNG 插入種子的機制,並用於測試。
- 在元件整合測試中使用模擬。請參閱「Realm Builder」。
- 在使用對不穩定行為敏感的測試時,請考慮多次執行測試,確保這些測試能持續通過。您可以使用重複的旗標,例如 GoogleTest 中的
--gtest_repeat
和 Go 中的--test.count
。如果您的測試容易在合併前喚醒,請盡量在本機執行至少 100-1000 次。
不建議使用:請勿在測試中使用 sleep
做為低強度同步處理的方式。在迴圈疊代之間進行輪詢時,您可以使用較短的睡眠。
測試替身:虛設常式、模擬、假
在測試期間,測試替身代表測試中程式碼的實際依附元件。
- 虛設常式是傳回指定值且不含任何邏輯的測試替身。
- 模擬是指具有預期呼叫方式的測試替身。模擬對測試互動很有幫助。
- 「假」是真實物件的輕量實作,
建議:為您擁有的程式碼建立假,讓客戶能在自己的測試中將該程式碼當做測試替身。如要進行整合測試,請考慮在測試領域中與系統的其他部分隔離執行實際元件的執行個體,並記錄這個行為。
不建議使用:請勿在測試中過度使用模擬,因為您可以建立較不易閱讀且維護成本低的測試,並降低通過測試的信心。請避免模擬非您擁有的依附元件。
相關資源:
適當使用端對端測試
建議:使用端對端測試測試關鍵使用者旅程。這類測試應以使用者的身分練習,例如自動進行使用者互動並檢查使用者介面狀態變更。
不建議使用:請勿使用端對端測試來涵蓋其他層級或範圍較小範圍的遺漏測試,因為這些端對端測試偵測到錯誤時非常難以排解。
建議:請謹慎使用端對端測試,做為平衡測試策略的一部分,這種測試策略會著重於快速執行並產生精確且可做為行動依據的結果。
不建議使用:請勿在開發意見回饋週期中仰賴端對端測試,因為這類測試通常需要執行時間較長,且通常比較小的範圍測試更不穩定。
相關資源:
- 要測試 UI 邏輯嗎?追蹤使用者!
- 進一步的端對端測試說不定
- Test Flakiness - 自動化測試的其中一個主要挑戰
- Test Flakiness - 自動化測試的其中一個主要挑戰 (第 2 部分)
- 避免不穩定的測試
- 不穩定的測試從何而來?