在寫程式的過程中,最讓人頭痛的就是當功能越來越複雜,修改某一塊程式碼時,突然發現別的地方出問題了。怎麼樣才能又快又好地確保程式碼沒毛病?這時候,測試就成了我們的好幫手。
很多人以為測試只是驗證程式碼的功能對不對,但其實它的作用比這更大。測試不僅可以幫我們找到問題,還可以讓程式碼變得更清晰、更好維護,甚至在未來功能變更時幫我們省下不少麻煩。測試的價值?
- 確認程式碼行為:確保它做的就是我們想要的。
- 提早發現問題:快速定位那些可能潛伏的 bug。
- 讓人放心改程式碼:有了測試,重構或新增功能時不用再提心吊膽。
- 省時又省力:自動化測試讓我們不用再重複做繁瑣的手動測試。
- 設計更好的程式碼:讓結構更清楚,也更容易被接手或修改。
每種類型的測試都有不同的測試目的和覆蓋範圍,可以從不同的角度來確保軟體的品質,而PHPUnit 支持多種不同的測試類型,包括單元測試、功能測試和功能測試…等。這裡主要會講到的兩大項為
Unit Test
跟Feature Test
。Unit Test(單元測試)
- 測試範圍:
- 單一類別、方法或模組的行為。
- 不依賴於外部系統或框架功能(如路由、中介層)。
- Mock 的使用:
- 將所有外部依賴(例如 Repository、Service)進行 Mock。
- 測試的重點是目標類別內的邏輯,而不是依賴的具體實現。
- 適用場景:
- 像
Service
\Repository
。 - 驗證方法是否正確調用依賴、處理資料和回傳結果。
- 像
Feature Test(功能測試)
- 測試範圍:
- 應用程式的完整功能流。
- 通常測試控制器行為,包括請求、回應和中介層的協作。
- Mock 的使用:
- 在需要模擬外部系統(如 API 請求)時使用 Mock,但大多依賴真實的資料和系統行為。
- 適用場景:
- 測試整個測驗功能,例如:
- 發送請求到
Controller
\Validation
。 - 通過 Mock Service 處理邏輯。
- 驗證回應是否正確。
- 發送請求到
Service
屬於 Unit Test 的原因
- 單一類別測試:
- 測試的是
Service
的方法是否能按照業務需求正確執行。
- 測試的是
- Mock 依賴:
- 測試中使用 Mock 的 Repository 和其他 Service,重點關注
Service
本身的邏輯。
- 測試中使用 Mock 的 Repository 和其他 Service,重點關注
- 與外部系統分離:
- 測試不涉及Controller、Route或Request流程。
如何結合 Feature 和 Unit 測試
- Unit Test:
- 對
Service
進行細粒度測試。 - 模擬所有外部依賴,驗證邏輯的正確性。
- 對
- Feature Test:
- 測試
Controller
是否正確調用Service
。 - 驗證整個功能流,包括請求和回應。
- 測試
這樣可以確保程式的不同層級都被充分測試,既有精細的單元測試,也有高層的整合測試。
單元測試的 3A 原則
- Arrange(準備): 設定測試所需的前置條件,包括初始化資料、模擬外部依賴等。
- Act(執行): 呼叫需要測試的方法或功能。
- Assert(驗證): 驗證執行結果是否符合預期。
如何執行測試?
使用 vendor/bin/phpunit
執行測試:
當你執行 vendor/bin/phpunit
,你實際上是在執行專案本地的 PHPUnit,這個版本是根據 composer.json
安裝的特定版本。
因為可能同時開發不同版本的專案,每個專案裡面的phpunit版本不一定一樣,所以進入docker容器,在下指令會比較不會出錯。
範例:
--filter {functionName} -> 只執行某一個測試
vendor/bin/phpunit Tests/Feature/Controllers/ExamControllerTest.php --filter testRegisterUsersSuccess
- 指定測試檔案:
Tests/Unit/Services/ExamServiceTest.php
- 指定測試方法:
--filter testSyncMercerAssessmentUpdatesDatabase
備註:
- 在 Windows 系統中,路徑分隔符是反斜線 (
\
),但由於反斜線在 CLI 中具有特殊含義(例如轉義),需要加倍反斜線來正確解析路徑。 - 如果使用 Linux 或 macOS,可以直接使用單斜線
/
小結
測試不僅能幫助我們檢查程式是否正確運作,還能促進程式碼的結構化與可維護性。在應用程式開發中,結合 Unit Test 和 Feature Test 可以確保程式邏輯細節與整體功能流都能無誤運行。
下一篇文章將進一步深入實際測試的應用範例,尤其是如何使用 Laravel 的 Factory 來建立測試資料,並搭配具體測試案例來演示 PHPUnit 測試的執行過程。我們將從測試資料的建立到完整測試的執行步驟,帶領大家實際操作,體驗單元測試與功能測試如何在開發流程中發揮威力。