還沒開始單元測試的你一定很忙:一個人也能開始單元測試

更新於 發佈於 閱讀時間約 5 分鐘

你有沒有過這種經驗:

  • 剛修完一個 bug,測完了,覺得很棒;結果才過幾天就又收到新的 bug 回報,原本修好的功能好像又壞了。
  • 每次調整了一點程式邏輯,就得在瀏覽器上點來點去,測完後才發現上次修的另一個地方又被影響了。
  • 感覺自己整天都在處理突發狀況、火燒屁股的事情,一天下來忙到翻,但卻說不出忙在哪裡。

如果你也有這些感受,那可能是因為「還沒開始單元測試的你一定很忙」。當我們沒有任何自動化測試時,開發過程中看似省事,但卻常常在後期付出更多的時間成本。這篇文章要和你分享:其實一個人就能開始單元測試,並透過一些簡單的測試,替自己「減輕」開發的負擔。

這麼做對我有什麼好處?

  1. 不用再手動一個一個按
    沒寫測試時,每次修改功能後,你可能就要打開瀏覽器,進行多種操作流程、點擊不同按鈕,直到確定「好像沒壞」才放心。但只要你建立了一兩個「簡單的自動化測試」,每次改完程式就能跑一下測試,程式會自動幫你做檢查,比手動測好多了。

    某次上線前,不小心改錯了某個Function導致計算結果都不正確,手動測試很難一下子發現。但有測試後,一跑測試就立刻紅燈警告,避免了正式上線的災難。

  2. 隨時知道程式哪裡壞掉
    有測試時,只要程式的某部分壞了,跑測試就能快速告訴你問題在哪裡,甚至在哪個函式或哪段程式碼。少了手動排查流程,也更能快速鎖定問題。
  3. 給自己多一層保護
    測試不只是給大公司或大團隊用的保護網,就算是自由工作者、Side Project 開發者,或是團隊裡最孤獨的我,也能靠「幾條測試」降低反覆 Debug、修 Bug 的風險。

為什麼大多數人還沒開始測試?

  1. 「感覺很難,不知道從哪開始」
    大部分初學者對測試的印象是「要寫很多莫名其妙的函數,而且一開始就要很複雜」。事實上,測試也可以很簡單,從最容易的函式測試下手就行。
  2. 「時間不夠、進度太趕」
    很多人認為寫測試會拖慢開發速度,「老闆都在催了,哪有時間寫測試?」然而,你現在沒花的測試時間,往往會在未來的 Debug 與重構中「雙倍奉還」。
  3. 「沒看到好處,覺得測試只是浪費時間」
    有些人沒親身體驗過測試帶來的效率提升,所以覺得只是不必要的額外工。對此,我們可以透過小規模的實驗、局部的測試來累積信心。

上面提到的只是常見阻力,並不代表所有人都如此。有些開發者早就把測試當成日常,也有團隊在某些專案中推行,但在其他專案卻沒時間做。每個環境都不一樣,需要具體情境來思考。

行動吧:一個人也能做什麼?

  1. 從「最常出包的功能」開始測
    • 想想看,你最常被報 bug 的功能是什麼?最常因一點小改動就壞掉的 module 又是哪個?先從這裡下手寫測試。
    • 舉例:一個常常要計算折扣的函式,或是一個複雜的字串處理邏輯。先寫幾條簡單的測試用例,確保輸入 A 就一定回傳 B。
  2. 分開小函式,單點測試
    • 單元測試英文叫作「Unit Test」,就是聚焦在「Unit」級別的小單位測試。
    • 如果你的程式碼是一整塊,可以嘗試把它抽出來成為獨立函式,再對這個函式寫測試。
  3. 挑戰「1 小時內完成第一個測試」
    • 別想太複雜,只需要:
      1. 安裝 PHPUnit(或任何你想用的測試框架),
      2. 新增一個測試檔,
      3. 裡面寫一個 testXxx() 方法,測試你想測的函式。
    • 跑一下測試,看它成功或失敗,就能體驗到測試最基本的流程。
  4. 用案例「證明」測試的價值
    • 在自己的專案裡面,主動記錄一下:自從你多寫了幾條測試後,是否在之後的改動中更快發現錯誤?或是手動測試的次數減少了?
    • 這樣的「證有」證明會是你在團隊或老闆面前宣傳測試時的好材料。

「還沒開始單元測試的你一定很忙」,不是一句隨便的口號,而是無數過來人累積下來的經驗談。

  • 單元測試帶來的好處,不需要等到團隊一起行動才看得到;只要你願意花一點時間嘗試,就能在日常開發中感受到有測試的踏實感。
  • 當然,僅僅靠一兩個測試檔,還不能代表已經完整覆蓋所有情境,但它至少能「證明」測試在某些情境下確實有效。

下一篇,我們一起正式進入 PHPUnit 的世界,教你如何安裝與撰寫第一個簡單的測試。只要做完下一篇,你就能從「不知道測試是什麼」進階到「寫出你的第一支測試」,幫助你一步一步往更完善的測試之路邁進。


文章回顧:

  1. 開場:描繪「忙到翻」的開發日常。
  2. 測試解決哪些忙亂:實際案例證明測試能幫忙。
  3. 為什麼還沒開始?:從心態、時間、環境探討一般阻力。
  4. 初步行動:一個人就能開始的簡易測試策略。
  5. 結論與引導:強調先有一些測試就能帶來改變,並預告下一篇關於 PHPUnit 的教學。

希望你能在看完本文之後,嘗試寫下你的第一隻測試,讓自己不再「忙到翻」而是「忙得有條不紊」!

如果你想知道如何安裝與使用 PHPUnit,敬請期待 走進 PHPUnit 的世界:從 0 到 1 的測試入門

這是一系列以軟體開發為主題的輕鬆分享,內容涵蓋了技術選擇、開發經驗、實戰應用等多方面的議題。無論是如何在眾多框架中做出選擇,還是如何應對技術轉移的挑戰,這裡有幽默、有趣的對話風格,將複雜的技術問題轉化為易懂的故事。
留言0
查看全部
avatar-img
發表第一個留言支持創作者!
在一個人資(HR)系統中,薪資結算與保費扣除是最核心的功能之一,扣員工的錢不能多算,該給政府的的也不能少算…。 不管是接手舊系統,還是開發新系統,只要隨著時間推移,每年勞健保的投保級距與費率都可能調整,
「嘿,你有聽說 PHP 8.4 的新特性了嗎?」新特性能在存取屬性時進行驗證、格式化,並支援虛擬屬性設計,程式碼更簡潔易讀,有助於維護和擴展。開發者可透過此特性快速實現自訂邏輯,同時保有工具相容性,讓整體開發流程更順暢、直觀。
CodeIgniter 3 和 Laravel 是兩種不同的 PHP 框架,各有其特點和適用場景。CodeIgniter 3 是一個輕量級框架,Laravel 是一個功能強大的現代 PHP 框架,同樣都有Models的它們有什麼樣的差別呢?
本篇文章為Laravel初學者提供了一個指南,深入探討了Laravel的routes目錄下的功能。文章詳細描述了web.php和api.php的差異和使用情境,並簡要介紹了console.php和channels.php的功能。透過這篇文章,讀者可以更好地理解和利用Laravel的路由功能。
Laravel框架中的路由系統是其核心功能之一,它允許開發者輕鬆地定義應用程式的URL結構和相應的邏輯。本篇文章將深入探討Laravel路由的基本概念、進階功能以及實際應用。
在Laravel的MVC架構中,視圖(View)是呈現資料給使用者的關鍵部分。本篇深入探討了視圖的基本概念、建立與管理、與資料的互動方式,以及Blade模板引擎的應用。Blade提供了一套強大的工具,使動態視圖建立更為高效。
在一個人資(HR)系統中,薪資結算與保費扣除是最核心的功能之一,扣員工的錢不能多算,該給政府的的也不能少算…。 不管是接手舊系統,還是開發新系統,只要隨著時間推移,每年勞健保的投保級距與費率都可能調整,
「嘿,你有聽說 PHP 8.4 的新特性了嗎?」新特性能在存取屬性時進行驗證、格式化,並支援虛擬屬性設計,程式碼更簡潔易讀,有助於維護和擴展。開發者可透過此特性快速實現自訂邏輯,同時保有工具相容性,讓整體開發流程更順暢、直觀。
CodeIgniter 3 和 Laravel 是兩種不同的 PHP 框架,各有其特點和適用場景。CodeIgniter 3 是一個輕量級框架,Laravel 是一個功能強大的現代 PHP 框架,同樣都有Models的它們有什麼樣的差別呢?
本篇文章為Laravel初學者提供了一個指南,深入探討了Laravel的routes目錄下的功能。文章詳細描述了web.php和api.php的差異和使用情境,並簡要介紹了console.php和channels.php的功能。透過這篇文章,讀者可以更好地理解和利用Laravel的路由功能。
Laravel框架中的路由系統是其核心功能之一,它允許開發者輕鬆地定義應用程式的URL結構和相應的邏輯。本篇文章將深入探討Laravel路由的基本概念、進階功能以及實際應用。
在Laravel的MVC架構中,視圖(View)是呈現資料給使用者的關鍵部分。本篇深入探討了視圖的基本概念、建立與管理、與資料的互動方式,以及Blade模板引擎的應用。Blade提供了一套強大的工具,使動態視圖建立更為高效。
你可能也想看
Google News 追蹤
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
如果你也是從事軟體相關工作的人,一定會遭遇突然需要你去學習一套你不熟悉的程式語言狀況吧,此時你會怎麼做呢? 是趕快去買書來看嗎? 還是趕快找一門程式課來上? 又或者乾脆去找會的同事來教學?
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
整合測試的時候突然遇到一個突然無法登入產品網站的問題,把程式模組單獨拉出來測試又正常,觀察測試報告後發現出現發生登入異常的時間點並不固定,而且只要發生就會連續發生一段時間,程式被中斷掉。後來確認問題在...
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 先讓我們規畫擬訂測試案例: 測試案例 當使用者瀏覽文章清單頁時: 使用者可看到所有文章清單,也就是【文章清單API】要能確實將資料庫內的文章資料,筆數不多不少地回應出來。 當使用者瀏覽單一文章頁時: 使用者可看到該文章資料,也就是【
今天要來為大家介紹幾個,在撰寫測試程式碼時可以利用的特殊函數。 setUp() & tearDown() setUp():我們可以在這個函數中,撰寫想要在每個測試案例函數執行前預執行的邏輯。 tearDown():我們可以在這個函數中,撰寫想要在每個測試案例函數執行後預執行的邏輯。 範例:
在之前的文章中,我們演練了許多測試方式,不過不知道大家有沒有發現,我們測試的大多是「正向」情況,「反向」的情況反而沒有測試到,也就是例外情況。 例外情況也可以測試嗎?當然可以! 本篇文章會為大家介紹如何「成功地測試失敗」。 例外測試函數 $this->expectException() 函
Thumbnail
大家好,我是woody,是一名料理創作者,非常努力地在嘗試將複雜的料理簡單化,讓大家也可以體驗到料理的樂趣而我也非常享受料理的過程,今天想跟大家聊聊,除了料理本身,料理創作背後的成本。
Thumbnail
哈囉~很久沒跟各位自我介紹一下了~ 大家好~我是爺恩 我是一名圖文插畫家,有追蹤我一段時間的應該有發現爺恩這個品牌經營了好像.....快五年了(汗)時間過得真快!隨著時間過去,創作這件事好像變得更忙碌了,也很開心跟很多厲害的創作者以及廠商互相合作幫忙,還有最重要的是大家的支持與陪伴🥹。  
Thumbnail
嘿,大家新年快樂~ 新年大家都在做什麼呢? 跨年夜的我趕工製作某個外包設計案,在工作告一段落時趕上倒數。 然後和兩個小孩過了一個忙亂的元旦。在深夜時刻,看到朋友傳來的解籤網站,興致勃勃熬夜體驗了一下,覺得非常好玩,或許有人玩過了,但還是想寫上來分享紀錄一下~
Thumbnail
打開 jupyter notebook 寫一段 python 程式,可以完成五花八門的工作,這是玩程式最簡便的方式,其中可以獲得很多快樂,在現今這種資訊發達的時代,幾乎沒有門檻,只要願意,人人可享用。 下一步,希望程式可以隨時待命聽我吩咐,不想每次都要開電腦,啟動開發環境,只為完成一個重複性高
Thumbnail
如果你也是從事軟體相關工作的人,一定會遭遇突然需要你去學習一套你不熟悉的程式語言狀況吧,此時你會怎麼做呢? 是趕快去買書來看嗎? 還是趕快找一門程式課來上? 又或者乾脆去找會的同事來教學?
Thumbnail
軟體系統的發展歷程大多相似,首重解決基本需求、提供操作介面,進而提升安全性、擴充功能、優化操作。
Thumbnail
整合測試的時候突然遇到一個突然無法登入產品網站的問題,把程式模組單獨拉出來測試又正常,觀察測試報告後發現出現發生登入異常的時間點並不固定,而且只要發生就會連續發生一段時間,程式被中斷掉。後來確認問題在...
在實務情境上,常會有在單一專案程式庫中,存取多個不同資料庫的使用情境,在這種情況下,我們通常會設置多個資料庫連線(Database Connection)設定。 在平常開發使用設很方便,但要做測試時就會發現一些問題: 在測試程式碼或 Seeder 中調用 factory() 時,都是在預設連線資
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 這次同樣地,先讓我們規畫擬訂測試案例: 測試案例 使用者註冊: 使用者可送出註冊資料,系統將建立使用者資料,並送出含有專屬驗證連結之驗證信,當此驗證連結被開啟後,將讓使用者轉為已驗證狀態 請求錯誤的驗證連結: 錯誤的驗證連結被開啟後
今天就讓我們依照前一天的情境題,來撰寫測試案例函數吧! 先讓我們規畫擬訂測試案例: 測試案例 當使用者瀏覽文章清單頁時: 使用者可看到所有文章清單,也就是【文章清單API】要能確實將資料庫內的文章資料,筆數不多不少地回應出來。 當使用者瀏覽單一文章頁時: 使用者可看到該文章資料,也就是【
今天要來為大家介紹幾個,在撰寫測試程式碼時可以利用的特殊函數。 setUp() & tearDown() setUp():我們可以在這個函數中,撰寫想要在每個測試案例函數執行前預執行的邏輯。 tearDown():我們可以在這個函數中,撰寫想要在每個測試案例函數執行後預執行的邏輯。 範例:
在之前的文章中,我們演練了許多測試方式,不過不知道大家有沒有發現,我們測試的大多是「正向」情況,「反向」的情況反而沒有測試到,也就是例外情況。 例外情況也可以測試嗎?當然可以! 本篇文章會為大家介紹如何「成功地測試失敗」。 例外測試函數 $this->expectException() 函