Python unittest 單元測試

當程式碼規模變大後,手動測試每個功能會變得極其低效。Python 內建的 unittest 模組借鑒了 Java 的 JUnit,提供了一套完整的框架來撰寫、組織與執行自動化測試。

基礎架構

要撰寫一個測試,你需要建立一個繼承自 unittest.TestCase 的類別,並定義以 test_ 開頭的方法。

# calculator.py (被測試的目標程式)
def add(a, b):
    return a + b

def divide(a, b):
    if b == 0:
        raise ValueError("除數不能為零")
    return a / b
# test_calculator.py
import unittest
from calculator import add, divide

class TestCalculator(unittest.TestCase):

    # 測試加法
    def test_add(self):
        self.assertEqual(add(1, 2), 3)
        self.assertEqual(add(-1, 1), 0)

    # 測試異常處理
    def test_divide_error(self):
        with self.assertRaises(ValueError):
            divide(10, 0)

# 直接執行這個檔案
if __name__ == '__main__':
    unittest.main()

常用的斷言 (Assertions)

斷言是用來判斷「實際結果」是否符合「預期結果」的方法:

方法檢查內容
assertEqual(a, b)a == b
assertNotEqual(a, b)a != b
assertTrue(x)bool(x) is True
assertFalse(x)bool(x) is False
assertIsNone(x)x is None
assertIn(a, b)a in b
assertRaises(Error)應該拋出特定異常

設置與清理:setUp 與 tearDown

如果每個測試方法都需要準備相同的環境(例如建立資料庫連線或讀取設定檔),可以使用 setUp()

class TestDatabase(unittest.TestCase):

    def setUp(self):
        # 每個測試方法執行「前」都會執行
        print("準備環境...")
        self.data = [1, 2, 3]

    def tearDown(self):
        # 每個測試方法執行「後」都會執行
        print("清理環境...")

    def test_sample(self):
        self.assertIn(1, self.data)

如何執行測試?

  1. 直接執行腳本python test_calculator.py
  2. 使用模組自動發現(最常用): 在專案根目錄執行以下指令,它會自動搜尋所有檔名為 test_*.py 的檔案並執行。
    python -m unittest discover
    

總結

撰寫單元測試雖然在初期會增加開發時間,但它帶來的好處是巨大的:

  • 防止回歸 (Regression):修改舊程式碼後,能快速確認是否破壞了現有功能。
  • 敢於重構:有測試保護,你才能大膽地改進代碼結構。
  • 作文件使用:測試案例本身就是最棒的程式碼範例。
如果你的專案很大,業界也常用第三方套件 pytest,它的語法更簡約且功能更強大,但底層仍然可以運行 unittest 寫的測試案例。