如何制定一個有效的測試策略

TestingGDR發表於2018-11-20

現在業界流行的測試金字塔和測試象限只是兩種高度抽象和簡化的測試策略模型,不具備實際可操作性,只具備高層次的指導性和參考性。直接根據這兩個模型來工作是低效的,甚至可能帶來負面效果。所以對於測試金字塔和測試象限不能盲目的使用,而是需要根據專案的實際情況來生成適合自己專案的測試策略和測試架構(專案不需要測試架構),並在此基礎上執行真實的測試工作。

測試分層

給不同的測試分類是一件令人煩惱的事。有功能測試,整合測試,單元測試,驗收測試,slow tests,fast tests,UI 測試... 等等等等。然後我們發現屬於我們的測試主要有三種型別:

  • 系統測試
  • 皮下測試
  • 單元測試

它們之間的區別主要在於被測試內容的範圍。系統測試指的是通過應用的外部介面進行運作,無論物件是一個瀏覽器,檔案下拉選單,佇列,window 窗體應用或者其他的什麼東西。

皮下測試執行在外部使用者介面之下。如果測試的是 Web 應用,皮下測試在我們理解就是指在真實的類

以及環境部署到位的情況下,通過命令處理器進行傳送的表單物件。繞過 UI 層邏輯,直接到達 domain 層。傳送表單物件,丟擲”成功 / 失敗”的執行結果。

對於最底層而言,我們有單元測試。單元測試用於測試一個類,並且可以是 fast test 或者 slow test 中的一種。Fast Test 即是常規的 TDD 測試,用於增量的類設計。Test doubles 曾被認為是必要的,但是除非系統互動非常值得關注,否則嚴格的 基於互動的測試 並不是那麼有價值。我們同樣也有 slow 單元測試,其同樣可被分類為 互動測試。當然它們同樣可歸類為 repository tests, persistence tests 等。

單元:皮下:系統 測試在我們的測試工作中各自佔的比重差不多是 10:2:1。 為了完成專案我們做了大約 5000 個單元測試,1000 個皮下測試,500 個使用 WaitN 以及 Gallio 驅動瀏覽器的系統測試。6000 個單元 / 皮下測試的執行時間大概是 10 分鐘,而剩下的 500 個 UI 測試大概需要 50 分鐘完成。

單元測試策略

單元測試是在嚴密的 TDD 模式下開發的。我們在功能實現之前編寫單元測試,並用這些測試驅動程式碼設計。這些測試可以幫助發現設計問題、封裝問題、程式碼異味等。

我們努力避免編寫純粹用於提供測試的程式碼。它們常常意味著我們有設計問題、責任錯位或封裝已被破壞。

隨著我們越來越深入專案管道,我們對互動測試的重視越來越少。 如果你真的對互動感興趣,那麼通過 mock 進行的互動測試也僅僅是有趣而已。但更多的時候,我們更感興趣的是附加作用,而互動只是一個實現細節。反之,我們經常做的是模擬(mock)出過慢或不可測的程式碼,比如儲存庫、基於外部服務的外觀、配置類等等。否則,我們有限的模擬只是模擬了我們感興趣的那些觀察點。

在大型專案中的某些時間點,為了提取出能加快功能交付的理念,設計往往需要做大型的重構。在我們上一個專案中,我們發掘出瞭如下理念:

  • AutoMapper
  • 將表單作為單獨的命令訊息處理
  • Input builders

有了以上這些,單元測試是重構時的保障。但只有我們依賴這些測試來捕獲應用程式中所有有趣的行為時,才能有保障的作用。為了允許有效的大中型重構,我們需要增加額外的測試層級。

皮下測試策略

皮下測試,顧名思義,所有的測試都是在使用者介面之下進行的。在 MVC 應用程式中,皮下測試是測試控制器下面的所有內容。對於 Web service,一切測試都在終端下進行。皮下測試的思想是,應用程式的最上層不執行任何實際的業務邏輯,而只是外部介面與底層服務之間的連線。

皮下測試的重要性體現在我們希望在拋開如使用者介面和外部服務這類外部連線點的情況下,能夠在整個系統執行的同時測試業務邏輯。相對於單元測試關注小模組的設計,皮下測試關注的不涉及設計,而是測試整個系統的基本輸入和輸出。

要建立有效的皮下測試,我們可以嘗試通過常見的邏輯流程建立 uniform pinch points。例如,我們可以建立一個命令訊息處理系統,或一個普通的查詢介面。在最近的一個處理批處理檔案專案上,批處理檔案中的每一行都被轉換為一條訊息。然後,我們創造一條訊息,傳送給這個系統,然後驗證處理該訊息的所有異常情況。

由於皮下測試不是基於設計而是基於高階(業務)行為,它們是理想的基於場景的測試策略,如 BDD 或Testcase Class per Fixture模式。如果我們要進行大的重構,我們需要這些高層次的測試,為商業行為建立全面的安全保障。由於皮下測試更關注於端對端的邏輯,所以它也是標誌功能點完成的一個重要的目標點。

雖然皮下測試使我們能夠安全地執行較大的重構,但它仍無法保證我們可以放心地將系統升級到生產環境。

全系統測試策略

起初,我們把全系統測試稱為“UI 測試”,直到我們的專案越來越多地牽涉到整合策略。這時輸入到我們系統中的不再是瀏覽器,取而代之的是訊息,來自 REST 端點、FTP 或批處理檔案。UI 測試只是全系統測試的一個子集。全系統測試背後的思想是,我們想按照軟體在生產環境中的使用方式來測試它們。對於一個 MVC 應用程式來說,就是基於瀏覽器的測試。對於批處理檔案來說,我們會使用實際的檔案。對於 REST 使用實際的 HTTP 請求。對於訊息則使用實際的佇列和訊息。

如果我們想知道,應用程式在部署到生產環境之前是否能按照預期工作,一個有效而且高效的方法是,建立一個自動化測試來測試整個系統。如果我可以讓 UI 測試登入到應用程式中、建立一個訂單,然後我可以驗證是否產生了一個訂單請求,那麼我會感覺很良好。

關於全系統測試的一個常見誤區是認為它就是黑盒測試。然而,全系統測試的特點在於,你必須對系統內部發生的事情瞭如指掌。實際上,全系統測試甚至還可以利用域模型來生成資料,而不是一個純粹為測試目的而構建的系統後門。很多團隊容易掉進去的一個大坑是,不按照與生產環境一樣的程式碼路徑來測試,這將導致系統處於古怪的、無效的、很難處理的狀態。

在我們的專案中,全系統測試程式碼是我們在聲稱一個功能 / 故事做完之前的所寫的最後程式碼。對於描述一個功能的“已完成”特性來說,手工測試的成本太高、而且不可靠。但是,如果我能像在生產環境一樣去測試,通過完全一樣的外部介面來完成,那這樣的手工測試也算是成功的。

全盤考慮

在一個未經測試過的應用程式中,作為提高覆蓋率的手段,我們發現實際上最有價值的測試策略是從全系統測試開始,然後往下移,直至單元測試。我們先做最寬鬆、最簡單的斷言,然後慢慢往下移,直至單元級別的邏輯。在全新開發的應用程式中,我們傾向於不只是特別關注某一個區域,因為對於一個需要長期維護的系統來說,所有的測試都很重要。

這種測試策略確實需要一定的投資。我們發現,當我們知道這個應用程式對客戶的業務有決定性作用的時候,這樣的全盤考慮在特別有效。如果一個應用程式對業務有決定性作用,那它將不得不面臨變更。當變更來臨的時候,我們最好能安全地實施變更而不影響客戶的業務。

結語:

最後跟大家推薦一個學習資料分享群:175317069,裡面大牛已經為我們整理好了許多的學習資料,有自動化,介面,效能等等的學習資料!

人生是一個逆水行舟的過程,不進則退,我們們一起加油吧!

 

相關文章