測驗:為什麼要寫測試?pytest 能幫你什麼?
共 5 題,點選答案後會立即顯示結果
1. 自動化測試相較於手動測試,最主要的優勢是什麼?
2. 文章提到測試的三個核心好處,下列何者不是其中之一?
3. 在測試金字塔中,哪種測試類型數量最多且執行最快?
4. pytest 相較於 Python 內建的 unittest,主要優勢是什麼?
5. pytest 的命名慣例中,測試檔案和函式的命名規則為何?
一句話說明
pytest 是 Python 的測試框架,讓你自動驗證程式碼是否正確運作。
為什麼需要自動化測試?
手動測試的痛點
想像你寫了一個計算折扣的函式:
def calculate_discount(price, discount_rate):
return price * (1 - discount_rate)
Code language: JavaScript (javascript)每次改動後,你可能會這樣手動測試:
# 在 Python 互動模式輸入
>>> calculate_discount(100, 0.1)
90.0 # 看起來對!
Code language: CSS (css)問題來了:
- 每次改動都要手動跑一遍
- 改了 A 功能,忘記測 B 功能
- 三天後你忘了要測哪些情況
- 其他人改你的程式碼,不知道要測什麼
自動化測試就是:把這些「手動驗證」寫成程式碼,讓電腦自動幫你跑。
測試的價值:三個核心好處
1. 信心
改完程式碼後,一行指令就知道有沒有弄壞東西:
pytest # 0.5 秒後告訴你:全部通過 / 哪裡壞了
Code language: PHP (php)2. 文件
測試程式碼就是「這個函式怎麼用」的範例:
def test_calculate_discount():
assert calculate_discount(100, 0.1) == 90.0 # 100 元打 9 折 = 90 元
assert calculate_discount(200, 0.25) == 150.0 # 200 元打 75 折 = 150 元
Code language: PHP (php)翻譯:「看測試就知道函式該怎麼用」
3. 重構保護
想改善程式碼結構?改完跑測試,通過就代表功能沒壞。
測試金字塔:三種測試層級
AI 在寫測試時,你可能會看到不同類型的測試。這裡簡單介紹:
/\
/ \ 端對端測試(E2E)
/----\ 整個系統跑一遍,最慢但最真實
/ \
/--------\ 整合測試
/ \ 多個元件一起測,中等速度
/------------\
/ \ 單元測試
/________________\ 單一函式,最快最多
| 測試類型 | 測什麼 | 範例 |
|---|---|---|
| 單元測試 | 單一函式 | calculate_discount() 計算正確嗎 |
| 整合測試 | 多個元件 | 資料庫 + API 一起運作正常嗎 |
| 端對端測試 | 整個流程 | 使用者從登入到結帳都順利嗎 |
Vibe Coder 重點:大多數時候你看到的會是「單元測試」,也就是測單一函式的那種。
pytest vs unittest:為什麼選 pytest?
Python 內建了 unittest 測試框架,但 pytest 更受歡迎。看看差異:
unittest 寫法(Python 內建)
import unittest
class TestDiscount(unittest.TestCase):
def test_basic_discount(self):
self.assertEqual(calculate_discount(100, 0.1), 90.0)
Code language: CSS (css)pytest 寫法
def test_basic_discount():
assert calculate_discount(100, 0.1) == 90.0
差異一目瞭然:
| 比較 | unittest | pytest |
|---|---|---|
| 需要寫 class | 要 | 不用 |
| 斷言語法 | self.assertEqual(a, b) |
assert a == b |
| 錯誤訊息 | 基本 | 超詳細 |
| 插件生態 | 少 | 超多 |
pytest 勝出的原因:
- 語法簡潔,少寫很多樣板程式碼
assert就是 Python 原生語法,不用學新東西- 錯誤訊息更清楚,直接告訴你哪裡不對
安裝 pytest
pip install pytest
或用 uv(更快):
uv pip install pytest
確認安裝成功:
pytest --version
# pytest 8.x.x
Code language: CSS (css)撰寫並執行第一個測試
步驟 1:建立測試檔案
建立 test_discount.py:
# test_discount.py
def calculate_discount(price, discount_rate):
"""計算折扣後價格"""
return price * (1 - discount_rate)
def test_basic_discount():
"""測試基本折扣計算"""
assert calculate_discount(100, 0.1) == 90.0
def test_no_discount():
"""測試沒有折扣的情況"""
assert calculate_discount(100, 0) == 100.0
def test_full_discount():
"""測試全額折扣"""
assert calculate_discount(100, 1) == 0.0
Code language: PHP (php)步驟 2:執行測試
pytest test_discount.py
Code language: CSS (css)輸出結果:
========================= test session starts ==========================
collected 3 items
test_discount.py ... [100%]
========================== 3 passed in 0.01s ===========================
翻譯:
collected 3 items:找到 3 個測試...:三個點 = 三個測試都通過3 passed:全部通過
步驟 3:看看測試失敗長什麼樣
故意寫一個會失敗的測試:
def test_wrong_expectation():
assert calculate_discount(100, 0.1) == 80.0 # 故意寫錯
Code language: PHP (php)執行結果:
========================= FAILURES =========================
_________________ test_wrong_expectation __________________
def test_wrong_expectation():
> assert calculate_discount(100, 0.1) == 80.0
E assert 90.0 == 80.0
test_discount.py:17: AssertionError
==================== 1 failed, 3 passed ====================
pytest 的錯誤訊息超清楚:
- 告訴你哪一行失敗
- 顯示實際值
90.0vs 預期值80.0
pytest 命名慣例
pytest 會自動找到測試,但你要遵守命名規則:
| 項目 | 規則 | 範例 |
|---|---|---|
| 檔案名稱 | test_ 開頭或 _test 結尾 |
test_discount.py, discount_test.py |
| 函式名稱 | test_ 開頭 |
def test_basic_discount(): |
| 類別名稱(可選) | Test 開頭 |
class TestDiscount: |
一句話:檔案和函式都用 test_ 開頭就對了。
Vibe Coder 檢查點
看到 AI 寫的測試時確認:
- [ ] 測試檔案是
test_開頭嗎? - [ ] 測試函式是
test_開頭嗎? - [ ] 有用
assert檢查結果嗎? - [ ] 測試案例涵蓋正常情況和邊界情況嗎?
- [ ] 能用
pytest指令執行嗎?
常見 pytest 輸出翻譯
| 符號 | 意思 |
|---|---|
. |
測試通過 |
F |
測試失敗(Fail) |
E |
測試出錯(Error,程式碼有 bug) |
s |
測試跳過(Skip) |
x |
預期失敗且真的失敗(xfail) |
本篇重點整理
- 手動測試痛點:容易遺漏、難以重複、沒有文件
- 自動化測試價值:信心、文件、重構保護
- 測試金字塔:單元測試最多最快,端對端測試最少最慢
- pytest 優勢:語法簡潔、assert 直覺、錯誤訊息清楚
- 基本使用:
pip install pytest+ 寫test_開頭的函式 + 執行pytest
下一篇預告
下一篇我們會學習 pytest 的核心功能:assert 的各種用法,以及如何組織測試檔案結構。
進階測驗:為什麼要寫測試?pytest 能幫你什麼?
測驗目標:驗證你是否能在實際情境中應用所學。
共 5 題,包含情境題與錯誤診斷題。
共 5 題,包含情境題與錯誤診斷題。
1. 你剛接手一個同事的專案,想了解 calculate_total() 函式應該怎麼使用。專案中有完整的測試檔案。最有效率的做法是什麼? 情境題
2. 你正在重構一個計算運費的函式,想改善程式碼結構但不改變功能。在重構前,你應該先做什麼? 情境題
3. 團隊決定導入自動化測試,你需要為一個電商網站選擇測試策略。根據測試金字塔原則,應該如何分配測試數量? 情境題
4. 小明建立了以下測試檔案,但執行 pytest 時完全沒有找到任何測試。問題最可能出在哪裡? 錯誤診斷
# 檔案名稱:discount_check.py
def check_basic_discount():
assert calculate_discount(100, 0.1) == 90.0
def check_no_discount():
assert calculate_discount(100, 0) == 100.0
5. 執行 pytest 後看到以下輸出,這代表什麼意思? 錯誤診斷
test_discount.py .F.s
==================== 1 failed, 2 passed, 1 skipped ====================