當我決定重新整理和分享這 30 天的測試學習歷程時,其實心裡有些忐忑。作為一個在軟體領域打滾了二十多年的開發者,我並不是什麼測試大師或技術領袖,只是一個在日常工作中不斷踩雷、學習、調整的普通工程師。
但正因為是這樣的身份,我更能體會在實際專案中導入測試的各種挑戰:時程壓力、團隊技能差異、既有程式碼的包袱、還有最近這幾年 AI 工具帶來的衝擊和變化。
我平常就有寫部落格文章,雖然這幾年的產量不多,因為大部分的寫作都是在公司裡寫技術文件,所以下班後就沒有多餘的心力再去寫文章。
其實一直有個想法就是將我對新人做教育訓練的單元測試和整合測試的教材做個整理然後寫出一系列的部落格文章,但就一直缺少動力。
直到今年四月時,在公司裡有個要寫出有關單元測試的教育訓練文件的機會,也有把訓練文件完成了基礎的部分,在寫的時候就有個想法,不如也趁這個機會去將這些內容做個整理,然後寫出一系列的文章,因為無法直接把公司那份已經寫好的文件帶出來然後直接使用。
就剛好藉著這次 ITHome 2025 鐵人賽的機會,以此為動力將這系列的文章給寫了出來。
又因為 AI 的進展再加上像 GitHub Copilot 這類的工具功能的增強與進步,讓過往不曾學習過單元測試的開發者,或是對於單元測試不熟悉,或是不知道怎麼寫單元測試的開發者,可以藉由這些工具就能夠自動產出單元測試的程式碼。
但這些開發人員因為對於單元測試的知識與技術不足,也就缺少了**「識讀」**這些 AI 產生的測試程式碼的能力,而導致無法判斷這些 AI 所寫的單元測試的正確性,也無法去確認這些測試程式碼是否真的有測試到使用情境、是否能夠依據規格達到驗證的目的,這些開發者只知道執行測試都通過就好。
然後等到系統在驗收或是上線後出現 BUG 或是需求變更時,這些測試程式碼就無法達到防止改 A 壞 B 的情況,也無法達到輔助開發的目的,反而會出現這些測試程式碼妨礙開發者進行程式修改的情況。
因為開發者還是要具備能夠寫出單元測試程式碼的能力,才有辦法去識讀並判斷 AI 所產生的測試程式碼。
這篇文章不是要總結什麼測試理論,而是想跟大家分享這 30 天來的學習重點,還有一些在實務上的心得。更重要的是,在這個 AI 工具越來越強大的時代,我們該如何看待和應用測試技術。
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
這一天我們談到了一個很重要的概念:AI 可以幫你寫程式碼,但不能幫你思考。 現在很多開發者習慣讓 AI 產生測試程式碼,但卻不知道這些測試在驗證什麼、有沒有意義。
當時我提到的一個觀點現在看來更加重要:在 AI 時代,理解測試的本質比會寫測試程式碼更重要。這不是說程式碼不重要,而是說如果你不知道為什麼要這樣測試,那麼再多的測試程式碼都可能只是自欺欺人。
我們也介紹了測試金字塔的概念:單元測試作為基礎、整合測試作為中堅、E2E 測試作為頂層。這個分層不只是技術問題,更是策略思考的體現。
在 .NET 的測試框架選擇上,我們最終選擇了 xUnit。不是因為它最流行,而是因為它的設計理念更符合現代測試的需求:每個測試都是獨立的實例、支援並行執行、有豐富的擴展機制。
現在回頭看,這個選擇是對的。在後面討論整合測試和並行執行時,xUnit 的這些特性就顯得格外重要。
Theory 和 InlineData 的組合讓我們可以用更簡潔的方式測試多種情境。Fact 和 Theory 的差別不只是語法,更代表了不同的測試策略:Fact 用於測試單一明確的行為,Theory 用於測試相同邏輯的不同輸入。
選擇 AwesomeAssertions 而不是 FluentAssertions 主要是考慮到授權問題。但使用下來發現,AwesomeAssertions 的表達力一點也不輸人。
result.Should().Be(expected)
這樣的語法讓測試的意圖變得更清楚。更重要的是,當測試失敗時,錯誤訊息也更容易理解。這在實際開發中特別重要,因為你不可能記住每個測試的細節。
Code Coverage 的學習讓我們理解到:測試覆蓋率不是萬能的,但是一個有用的輔助指標。重點是要知道如何正確解讀和使用這些指標,而不是盲目追求 100% 的覆蓋率。
人稱敏捷三叔公的柯仁傑老師於這次 ithome 2025 鐵人賽,有寫《如何利用實例化需求在 GenAI 時代下自我升級》的系列文(在30 天內帶你用範例說人話,搞懂需求、搞定驗收,走出專案混亂的輪迴),是可以讓開發者或是開發團隊的 PM、SA、SD、QA 都能夠從中有所收穫。
系列文章連結:如何利用實例化需求在 GenAI 時代下自我升級
這個系列特別適合解決測試情境制定的問題,因為它教你如何從需求中萃取出具體的使用場景,而這些場景正是測試案例的重要來源。
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
這個階段我們進入了測試的核心:如何處理外部依賴。我印象深刻的是當時提到的一個觀點:測試替身不是為了模擬,而是為了隔離。
很多人以為 Mock 就是要完全模擬真實的外部系統,但實際上我們要的是隔離待測系統,專注測試核心邏輯。這個思維的轉換對我後來的測試設計影響很大。
ITestOutputHelper 看起來是個小工具,但在實際除錯時特別有用。當測試失敗時,能夠看到詳細的執行過程,這對定位問題非常重要。這一天也讓我理解到:測試不只是驗證功能,也是建立系統可觀測性的重要環節。
Day09 討論的問題很實際:要不要測試私有方法?我學到的重要觀念是:如果你經常需要測試私有方法,可能是設計出了問題。 這不是技術問題,而是設計問題。好的設計自然就有好的可測試性。
AutoFixture 是個遊戲規則改變者。以前我們花大量時間在準備測試資料,現在可以讓 AutoFixture 自動產生。但更重要的是,它讓我們專注在測試邏輯本身,而不是被測試資料的準備工作分散注意力。當然,知道什麼時候要自訂 AutoFixture 的行為也很重要。
將 AutoFixture 和 NSubstitute 結合使用,可以大大簡化測試的準備工作。AutoData 屬性讓參數化測試變得更加簡潔,這在實際專案中特別有用。
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
這個階段讓我深刻理解到:有些東西看起來難測試,其實是設計問題,不是測試問題。
AutoFixture 與 NSubstitute 的整合讓我看到了自動化測試的另一個層次。當你可以自動產生 Mock 物件和測試資料時,測試的準備工作幾乎可以忽略不計,讓你真正專注在測試邏輯本身。
Bogus 與 AutoFixture 的比較讓我學會了工具選擇的思考方式:不是哪個工具更好,而是哪個工具更適合當前的場景。AutoFixture 適合快速建立大量測試資料,Bogus 適合需要精確控制資料格式的場景。
時間是測試中最難處理的元素之一。DateTime.Now
讓測試結果變得不可預測。Microsoft.Bcl.TimeProvider 提供了一個優雅的解決方案。TimeProvider.System
用於正常執行,FakeTimeProvider
用於測試,這樣的設計讓時間相關的邏輯變得可測試。
這個系列讓我理解到抽象化不只是為了測試,更是為了程式碼的可維護性。好的抽象化設計讓程式碼既容易測試,也容易理解和修改。
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
從單元測試跳到整合測試,不只是技術的改變,更是思維的轉換。單元測試關注個別元件的行為,整合測試關注元件之間的協作。這個轉換過程中,我學會了如何平衡測試的範圍和複雜度。
檔案 I/O 是另一個測試難點。System.IO.Abstractions 讓我們可以在測試中使用記憶體檔案系統,避免了真實檔案操作的複雜性。這也讓我理解到抽象化不只是為了測試,更是為了程式碼的可維護性。
Testcontainers 是整合測試的利器。可以在測試中啟動真實的資料庫、快取、訊息佇列,讓測試環境更接近正式環境。但也學到了容器管理的重要性:資源清理、並行執行的考量、測試執行時間的最佳化。
EF Core、Dapper 的測試策略各有不同。.NET Aspire 的整合測試模式提供了一個現代化的解決方案,特別適合微服務架構。這個系列讓我看到了測試技術的發展趨勢:從單體應用到微服務、從手動測試到自動化、從隔離測試到真實環境模擬。
並行測試執行、效能最佳化、疑難排解,這些都是在實際專案中會遇到的挑戰。最重要的是建立一套系統性的方法來處理這些問題。
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
內容大綱:
文章連結:
這個階段讓我思考了測試技術的未來發展方向。
AI 輔助測試開發是個有趣的話題。GitHub Copilot 可以幫你寫測試程式碼,但重要的問題是:它知道要測試什麼嗎?這讓我更加確信:在 AI 時代,理解測試的本質比會寫測試程式碼更重要。
TUnit 代表了新一代測試框架的發展方向:更快的執行速度、更好的開發者體驗、更現代的架構設計。雖然 xUnit 仍然是主流選擇,但了解這些新技術有助於理解測試工具的演進趨勢。
特別是在 Day29 和 Day30 中,我們學習了了如何使用 TUnit 的進階功能:
在學習測試理論時,一切看起來都很美好:寫測試、重構、持續整合,彷彿只要按照步驟做就能擁有高品質的程式碼。但真正在專案中實施時,才發現現實遠比理論複雜。
最大的挑戰通常不是技術問題,而是人的問題。團隊成員對測試的認知不同、時程壓力下的優先順序考量、既有程式碼的技術債等等。我遇過開發者抱怨「寫測試比寫功能還花時間」,也遇過 PM 質疑「測試不能直接交付給客戶,為什麼要花時間寫?」
但經過這幾年的實踐,我發現測試帶來的價值遠超過投入的成本。最明顯的改變是重構的信心:當你要修改一段複雜的邏輯時,有測試保護讓你敢於大膽調整;當你發現 bug 時,先寫個失敗的測試,然後修復到測試通過,這樣可以確保同樣的問題不會再出現。
剛開始推動測試時,團隊很容易陷入覆蓋率的迷思。看到覆蓋率報告上 90% 的數字就覺得安心,但實際上可能都是一些沒有意義的測試。
我並沒有整個專案的 Code Coverage 的迷思,不會去追求那個數字要達到多少,也不會執著於每個方法都要有測試去覆蓋到。對於重要的、複雜的邏輯,我就會盡量去增加測試,這麼做不是為了要提高 Code Coverage 的數字,而是從逐漸增加測試去驗證這些邏輯,讓我能夠有信心去確保我所寫出來的程式碼是在對的方向,而 Code Coverage 的提升只是附加作用而已,並不是重點。
我現在更注重測試的品質而不是數量。一個設計良好的測試,能清楚表達業務邏輯、容易維護、失敗時能快速定位問題,這比十個只是為了提高覆蓋率而寫的測試更有價值。
比如說,測試 getter/setter 方法可能可以提高覆蓋率,但對品質改善沒什麼幫助。相反地,測試一個複雜的業務規則驗證邏輯,即使只有一個測試,也比前面十個 getter/setter 測試更有價值。
在對新人的教育訓練時,因為新人常常執著於程式的實作,而測試的效益對新人來說還不會有那麼深刻的體會,畢竟開發經驗的影響也是有絕大的關係。新人總是會問到,要寫多少的測試才足夠?或是會問 Code Coverage 要達到多少才是標準?
我的回答是:你的每次簽入後的 Code Coverage 要能夠比上次的數據還要多一些,既使多 0.01% 也可以。
這樣的引導方式有幾個好處:避免新人被絕對數字嚇到、建立漸進改善的習慣、讓新人專注在有意義的測試上,而不是為了達到某個覆蓋率目標而寫無意義的測試。重點是培養持續改善的心態,而不是追求完美的數字。
回顧我當初在團隊導入單元測試的經驗,這確實對開發團隊來說是增加了寫程式的工作,也是增加了開發流程。但我並沒有強制每個專案都必須要導入,而是採取漸進式的推動策略。
對於有導入單元測試的專案團隊,我也不會把 Code Coverage 作為 KPI 的項目,因為我相當反對這種 KPI 的制訂。正如董大偉老師所說的:「有導入就會有抗拒,有推動就會有阻力」,這句話我經常引用,因為它深刻地點出了推動任何新技術或流程時的根本挑戰。
當初資訊單位的主管真的是有提出這種加入 KPI 項目的要求,而我當時是極力反對的,甚至對主管說:「如果真的要列入 KPI 項目的話,那還是不要導入單元測試。」
這個立場可能看起來很極端,但我深知一旦將 Code Coverage 當作 KPI,開發者就會為了衝數字而寫沒有意義的測試,完全失去了測試的本質。測試應該是為了建立信心、保證品質,而不是為了達成某個數字目標。
這個經驗讓我更加確信:推動測試文化需要的是耐心和正確的引導,而不是強制的數字指標。
TDD(Test-Driven Development)是測試領域經常被討論的話題。我知道有很多開發者是 TDD 的實踐者和擁護者,他們在專案中成功運用 TDD 並獲得了良好的效果。
就我個人的工作經驗而言,我採用的是「即時測試補強」的方式:並不是等整個類別或專案完成後才寫測試,而是當一個方法完成後,或是方法實作到一個階段後,就立即為其補上測試。這樣的做法能讓我確保方法的實作保持在需求規格範圍內,也能及時驗證實作的正確性和符合需求程度。
這種方式介於傳統的「測試後行」和 TDD 之間,既保有了實作時的彈性,又能即時透過測試來驗證和約束程式碼的品質。我認為不管是 TDD、「測試後行」還是「即時測試補強」,最重要的是要有測試。每個團隊和專案都有不同的特性,重點是找到適合自己的方式,並且持續改善程式碼品質。
推動測試文化最困難的是改變習慣。我嘗試過幾種方法:
漸進式導入:不要一開始就要求 100% 的測試覆蓋率,從新功能開始要求寫測試,讓團隊慢慢習慣。
Pair Programming:讓有測試經驗的開發者和新手一起寫測試,這比單純的教育訓練更有效。
工具支援:建立好的 CI/CD 流程,讓測試執行變得簡單,測試結果一目了然。
分享成功案例:當測試幫助快速定位問題或防止回歸錯誤時,在團隊中分享這些成功經驗。
最重要的是,身為團隊中的資深成員,要以身作則。如果連你自己都不寫測試,很難期待其他人會重視測試。
說實話,要跟大家分享一個可能比較沮喪的事實:我過去在前一家公司推動單元測試以及做教育訓練有將近 10 年,但最終的結果是只有部分認同的開發者才有在專案裡加入單元測試,而加入整合測試更是少之又少。
更讓人無奈的是,之前的公司甚至最後是有些單位主管表示不想讓開發人員去寫單元測試,因為他覺得那些寫測試的時間還不如拿去消化更多的需求,他要的是趕快做、趕快上線,有錯再趕快改。這種短視近利的思維,完全忽略了測試帶來的長期價值。
而我現在的團隊則是只有我一個人有寫單元測試,其他團隊雖然也有寫,但是單元測試的品質很差,看不出測試的目的與意義,就只是拿來驗證程式碼的可行性,而沒有情境,這些測試無法作為程式碼的說明書。
這些經驗讓我深刻體會到:推動測試文化不只是技術問題,更是組織文化和管理思維的問題。 當組織追求的是短期交付速度而不是長期程式碼品質時,再好的技術推廣都可能徒勞無功。
但我並不因此感到完全失望,因為我相信:
重要的是保持耐心,持續以身作則,並且在適當的時機分享測試帶來的價值。
接下來我要說的是過去對新人做教育訓練,甚至於專案開發時其他開發人員都會遇到的問題:不知道要寫那些測試,或是不知道有哪些是測試情境,不知道測試案例從何而來、也不知道怎麼訂定測試案例。
或許是開發經驗比較多了一些,所以當我接到需求或是看到規格時,我大致上就能夠知道會有哪些測試情境要做,也能夠訂定出有多少個測試案例。隨著程式實作逐漸完整,原本的測試案例也會去做調整,可能變得更多,變少也有可能,因為需求規格總是會有變化。
有 SD 或是 SA 能夠給測試案例是更好,但常常所遇到的是只有規格而沒有測試案例。所以很多開發人員就會對於要寫什麼測試案例就會很迷惘,因為他們不會從需求規格去抓出有哪些測試情境。
對新人做教育訓練時,在單元測試的訓練時,我會採用這樣的步驟:
在檢視的過程中,我會發現到可能是他們原本程式設計有瑕疵或是缺少一些邏輯判斷,就會要他們去調整程式,也會讓他們再去修改測試情境。等到所有測試情境和測試案例都讓我檢視完成後,我才會讓他們去實作出單元測試。
測試案例對於很多開發人員是個相當棘手的項目,因為就如同我前面所說的,開發者對於自己已經實作完成的程式碼,無法訂定出要怎麼驗證的測試案例。對於開發者來說,他們認為的實作完成就表示做好了、沒問題、等到別人使用時有 BUG 再來改。
這個問題的根源在於:開發者往往從實作的角度看程式碼,而不是從使用者或需求的角度看功能。 他們知道程式碼怎麼運作,但不一定知道這個功能在什麼情況下會被使用,以及可能遇到哪些異常狀況。
整合測試最大的挑戰是環境配置。單元測試在記憶體中執行,速度快、隔離性好。但整合測試需要真實的資料庫、快取、外部服務等等,複雜度立刻提升好幾個層級。
我遇過最頭痛的問題是測試環境的不一致性。開發者的本機環境、CI 伺服器、測試環境,每個地方的配置都可能不同,導致測試在某些地方會過、某些地方會失敗。
Testcontainers 在很大程度上解決了這個問題。透過 Docker 容器,我們可以在測試中啟動一致的環境,不管是在開發者的本機還是 CI 伺服器上都一樣。但這也帶來了新的挑戰:Docker 環境的設定、容器的生命週期管理、資源的清理等等。
整合測試中的測試資料管理是另一個大坑。不像單元測試可以用 AutoFixture 產生假資料,整合測試需要在真實的資料庫中建立測試資料。
我試過幾種策略:
每個測試都建立獨立的資料:這樣隔離性最好,但會讓測試執行時間變得很長。
共享測試資料:執行速度快,但測試之間可能會互相影響。
還原交易:在測試結束時還原交易 (rollback),這樣可以保持資料庫的乾淨,但不是所有情況都適用。
資料庫重建:每次測試前都重建資料庫,確保一致性,但執行時間會很長。
現在我傾向於混合策略:基礎資料使用共享的 Seed Data,測試特定的資料在測試中建立,並在測試結束時清理。
整合測試的執行時間通常比單元測試長很多,所以並行執行看起來很誘人。但實務上,我的經驗是:
整合測試不建議使用並行:雖然並行執行可以節省時間,但隨之而來的測試資料覆蓋與錯亂問題,更會造成測試的不穩定。整合測試通常涉及共享資源(資料庫、檔案系統、網路服務),並行執行容易產生:
單元測試的並行考量:一般的單元測試,除非測試方法多到誇張的數量,不然還是盡可能不使用並行執行。原因包括:
實務建議:我現在的策略是優先保證測試的穩定性和可靠性,時間節省是次要考量。如果真的需要並行執行,會先確保:
經過這麼多年的經驗,我發現選擇測試工具不只是技術問題,更是策略問題。我現在會從幾個角度來評估:
學習成本:團隊需要多少時間來熟悉這個工具?是否有足夠的文件和社群支援?
整合能力:工具能否與現有的技術棧良好整合?是否支援我們使用的 CI/CD 平台?
長期維護:工具的維護狀況如何?背後有穩定的組織支持嗎?授權條件是否合理?
擴展性:當專案變大變複雜時,工具能否跟上需求?
成本效益:投入的學習和導入成本,相對於帶來的效益是否合理?
在不同類型的專案中,我會選擇不同的工具組合:
小型專案或原型開發:簡單的工具組合就夠了,xUnit + 內建的 Assert,重點是快速驗證概念。
中型企業應用:xUnit + AwesomeAssertions + NSubstitute + AutoFixture,這個組合能應付大部分的測試需求。
大型分散式系統:除了上面的工具,還需要加上 Testcontainers、.NET Aspire Test Projects,以及各種效能測試工具。
遺留系統維護:可能需要更多的 Mock 工具和適配器,來處理難以測試的舊程式碼。
重點是不要為了用新工具而用新工具,要根據實際需求來選擇。
我學到一個重要教訓:不要一次導入太多新工具。每個工具都有學習曲線,如果同時導入多個工具,團隊會感到負擔很重。
我現在的做法是階段性導入:
每個階段都要給團隊足夠的時間來適應,並且要有明確的成功指標。
GitHub Copilot 和 ChatGPT、Claude、Gemini 等 AI 工具讓寫測試程式碼變得容易很多。只要給個提示,AI 就能產生看起來很完整的測試程式碼。語法正確、結構清楚、甚至還會用適當的 Mock 和 Assert。
但我發現了幾個問題:
AI 產生的測試往往缺乏業務邏輯的深度理解。它可能會測試所有的程式路徑,但不一定測試所有的業務情境。比如說,一個訂單處理的邏輯,AI 可能會測試正常流程和例外處理,但可能會遺漏一些邊界情況:庫存不足時的處理、優惠券過期的情況、會員等級的特殊規則等等。
測試的意圖表達不夠清楚。AI 產生的測試通常會有很制式的命名:Test_Method_Should_Return_Expected_Result
,但這樣的命名並不能清楚表達測試的業務意圖。一個好的測試名稱應該像是 當庫存不足時_下訂單_應該拋出庫存不足異常
。
對測試策略的思考不足。AI 可能會為每個 public 方法都產生測試,但不會思考哪些測試是真正有價值的。結果就是產生了一堆低價值的測試,反而增加了維護負擔。
AI 很會寫語法正確的程式碼,但對於測試品質的判斷就不那麼可靠了。我遇過一些例子:
過度 Mock 的問題:AI 傾向於 Mock 所有的依賴,包括一些可能不需要 Mock 的簡單物件。結果是測試變得很複雜,但實際測試價值不高。
測試資料的不合理性:AI 產生的測試資料可能在語法上正確,但在業務邏輯上不合理。比如產生一個負數的年齡、或是一個未來日期的出生日期。
測試覆蓋的盲點:AI 容易產生能讓覆蓋率報告好看的測試,但可能遺漏了真正重要的業務路徑。
我現在的做法是:讓 AI 幫我產生測試的骨架,但一定要自己檢查和調整測試的邏輯和資料。
在 AI 可以快速產生測試程式碼的時代,我越來越覺得理解測試原理比會寫測試程式碼更重要。
測試策略的規劃:什麼時候需要單元測試、什麼時候需要整合測試、如何平衡測試的範圍和執行時間,這些都需要人來判斷。AI 可能會建議你為每個方法都寫單元測試,但實際上某些簡單的 DTO 轉換可能不需要測試。
業務邏輯的理解:測試不只是程式碼的驗證,更是業務需求的體現。一個了解業務邏輯的開發者能寫出真正有價值的測試,而 AI 只能根據程式碼的結構來產生測試。
測試維護的判斷:當需求變更時,哪些測試需要修改、哪些測試可以保留、哪些測試應該刪除,這些判斷需要對系統有深度理解的人來做。
我覺得在 AI 時代,測試工程師(或者說有測試技能的開發者)的核心競爭力在於:
測試思維:能夠從使用者的角度思考系統的行為,設計出有意義的測試情境。
系統性思考:能夠從整個系統的角度來規劃測試策略,平衡不同層級測試的比重。
品質判斷:能夠判斷測試的價值,識別出高價值的測試和低價值的測試。
問題診斷:當測試失敗時,能夠快速定位問題的根因,判斷是程式碼問題還是測試問題。
這些能力都需要經驗的累積和思考的訓練,不是 AI 能夠輕易取代的。
我現在使用 AI 輔助測試的策略是:
用 AI 來產生測試程式碼的骨架:讓 AI 幫我建立基本的測試結構、Mock 設定、Assert 語法等等。
自己思考測試的業務邏輯:測試什麼情境、用什麼資料、期望什麼結果,這些都要自己決定。
用 AI 來改善測試程式碼的品質:讓 AI 幫我檢查測試的命名、重構重複的程式碼、優化測試的可讀性。
保持對 AI 建議的批判性思考:不要照單全收 AI 的建議,要根據專案的實際情況來判斷。
根據我的經驗,AI 在以下幾個方面特別有用:
重複性的程式碼產生:建立相似的測試結構、產生大量的測試資料、寫重複的 Mock 設定等等。
語法和格式的優化:改善測試程式碼的可讀性、統一命名規範、重構重複的程式碼。
測試程式碼的除錯:幫助找出測試程式碼中的語法錯誤、邏輯問題等等。
文件和註解的產生:為複雜的測試邏輯產生說明文件、為測試方法產生清楚的註解。
而人類應該專注在:
測試策略的規劃:決定測試的範圍、層級、優先順序等等。
業務邏輯的驗證:設計能真正驗證業務需求的測試情境。
測試品質的評估:判斷測試的價值、識別測試的盲點、評估測試的維護成本。
問題的診斷和解決:當測試失敗時,分析問題的根因並找出解決方案。
團隊協作和知識傳承:推動測試文化、訓練團隊成員、建立測試的最佳實踐。
但不管技術如何發展,我相信人類的判斷力和創造力在測試領域仍然是不可取代的。
經過這 30 天的整理和反思,我覺得未來值得關注的測試技術方向有幾個:
雲原生測試技術:隨著容器化和微服務的普及,Testcontainers、.NET Aspire 這類工具會變得更重要。學會在分散式環境中設計和執行測試,是未來的必備技能。
AI 輔助測試:不是要取代人類,而是要學會如何有效地與 AI 協作。理解 AI 的優勢和限制,建立良好的人機協作流程。
效能和可靠性測試:隨著系統規模的增大,效能測試、混沌工程、可靠性測試這些領域會變得更重要。
測試策略和架構:技術會不斷變化,但測試的原理和策略相對穩定。投資時間理解測試策略、測試架構設計,會有長期的回報。
如果你想開始或改善測試實踐,我的建議是:
從新功能開始:不要嘗試為整個舊系統補測試,從下一個新功能開始要求自己寫測試。
選擇簡單的工具組合:xUnit + 基本的 Assert 就夠了,不要一開始就使用太多工具。
專注在核心業務邏輯:為最重要的業務邏輯寫測試,不要為了覆蓋率而測試 getter/setter。
先學會寫好的單元測試:理解 3A 原則、學會合理的 Mock、寫清楚的測試名稱。
再學習整合測試:當單元測試變成習慣後,開始學習整合測試的技巧。
最後學習進階工具:AutoFixture、Testcontainers 這些工具,等你有了基礎再學習。
以身作則:自己先開始寫測試,用實際行動證明測試的價值。
分享成功案例:當測試幫助解決問題時,在團隊中分享這些經驗。
循序漸進:不要期望一夜之間改變整個團隊,給大家足夠的時間適應。
寫完這 30 天的測試修練總結,我最大的感悟是:測試不只是技術問題,更是思維問題。
在這個 AI 工具越來越強大的時代,我們不需要擔心被取代,而是要學會如何更好地利用這些工具。AI 可以幫我們寫程式碼,但不能幫我們思考;AI 可以產生測試,但不能替我們判斷測試的價值。
測試的核心價值在於幫我們建立對程式碼的信心,讓我們敢於重構、敢於改變。這個價值不會因為技術的演進而消失,反而會變得更加重要。
回到前言中提到的那個老派工程師的身份認同,經過這 30 天的整理和反思,我發現所謂的「老派」其實是一種堅持:堅持品質、堅持原則、堅持在快速變化的技術浪潮中保持理性思考。不管 AI 如何發展,這些基本功永遠不會過時。
我希望這 30 天的分享能對大家有所幫助。測試修練是一個持續的過程,沒有終點,只有不斷的改善和學習。
但對於某些人來說,也許這些過往被認為很難學起來、很難上手的測試技術,在往後 AI 技術逐漸發展成熟後,大概也沒多少人會再去重視並且去學怎麼寫測試了。
藉由這 30 天的修練,除了將我過去應用在工作上經驗寫下來並且分享給大家之外,也是讓這些測試技術可以留下來做個記錄,因為假以時日,我也可能因為 AI 的使用而逐漸忘記該怎麼寫測試,希望到了那個時候我還可以回過頭來看看這些記錄,讓我能夠重拾記憶,喚起我過去的測試經驗。
感謝大家跟我一起完成了這 30 天的測試修練之旅。如果這個系列對你有幫助,歡迎分享給其他需要的開發者。讓我們一起建立更好的軟體品質文化!