1. Python unittest 是什麼?
unittest
是 Python 標準函式庫中包含的單元測試框架,對於確保程式碼品質至關重要。它允許開發者對程式碼的各個部分進行獨立測試,以便及早發現錯誤。此外,在持續開發過程中,它有助於確保程式碼的變更不會破壞既有功能。
單元測試的重要性
隨著程式碼變得更加複雜,確保不同部分能夠正確協同運作變得越來越困難。透過引入單元測試,可以更容易防止小幅度變更導致的意外錯誤,並保持整個程式的穩定性。
2. unittest 的基本用法
unittest
的基本概念是建立一個繼承自 unittest.TestCase
的類別,並在其中定義測試方法。在測試方法內,可以使用 assertEqual()
等斷言方法來比較預期結果與實際結果。
基本測試範例
以下範例測試 add(a, b)
函式的運作方式:
import unittest
# 被測試的函式
def add(a, b):
return a + b
# 測試類別
class TestAddFunction(unittest.TestCase):
def test_add_integers(self):
result = add(2, 3)
self.assertEqual(result, 5)
if __name__ == '__main__':
unittest.main()
在這段程式碼中,我們測試 add()
函式是否正常運作。assertEqual()
方法用來確認預期值與實際結果是否相符。透過這種方式,可以驗證函式在不同情境下的正確性。
擴展測試
可以使用多個測試方法來測試函式對不同輸入的行為,例如測試浮點數或字串的相加:
def test_add_floats(self):
result = add(2.5, 3.5)
self.assertAlmostEqual(result, 6.0, places=2)
def test_add_strings(self):
result = add("Hello, ", "World!")
self.assertEqual(result, "Hello, World!")
透過這種方式,測試函式對不同類型的數據輸入的表現,確保它能夠在各種情境下正常運作。

3. setUp() 與 tearDown() 的使用方法
如果需要在測試執行前後自動執行特定處理,可以使用 setUp()
和 tearDown()
方法。這些方法可用於在測試開始前進行必要的初始化,以及在測試結束後進行清理工作。
setUp() 的範例
setUp()
方法會在每個測試方法執行前自動被呼叫,可以將共用的初始化過程集中在這裡。
def setUp(self):
self.temp_value = 42
tearDown() 的範例
tearDown()
方法會在每個測試方法執行後被呼叫,用來執行後續處理,例如釋放資源或刪除暫存檔案。
def tearDown(self):
self.temp_value = None
透過這種方式,可以減少測試代碼的冗餘性,使測試程式碼更加清晰且易於維護。
4. 使用 Mock 進行依賴測試
當測試的程式碼依賴外部資源(例如資料庫、API 服務等)時,可以使用 Mock 來取代這些依賴,從而提高測試執行速度並確保測試結果的可預測性。Python 的 unittest.mock
模組能夠幫助我們輕鬆實現這一點。
Mock 的實際範例
以下範例將一個執行時間較長的函式 time_consuming_function()
替換為 Mock:
from unittest.mock import patch
class TestAddFunction(unittest.TestCase):
@patch('my_module.time_consuming_function')
def test_add_with_mock(self, mock_func):
mock_func.return_value = 0
result = add(2, 3)
self.assertEqual(result, 5)
在這個範例中,透過 Mock 取代 time_consuming_function
,讓測試在不執行該函式的情況下完成,這樣可以縮短測試時間,同時仍能確保正確的測試結果。

5. 例外處理與自訂斷言
在 unittest
中,也可以測試例外處理。例如,可以使用 assertRaises()
來確認特定情境下是否正確拋出例外。
測試例外處理
以下範例測試當除數為 0 時,是否會正確拋出 ZeroDivisionError
。
def test_divide_by_zero(self):
with self.assertRaises(ZeroDivisionError):
divide(1, 0)
這段程式碼會測試 divide(1, 0)
是否拋出 ZeroDivisionError
,確保程式能夠正確處理異常狀況。
建立自訂斷言
當標準斷言方法無法滿足測試需求時,可以建立自訂斷言方法來提高測試的可讀性與靈活性。
def assertIsPositive(self, value):
self.assertTrue(value > 0, f'{value} 不是正數')
透過自訂斷言,可以更清楚地表達測試邏輯,使測試更加直觀。
6. unittest 的測試探索功能
unittest
提供了測試探索(Test Discovery)功能,能夠自動搜尋專案中的所有測試檔案並執行測試。這在大型專案中特別實用。
如何使用測試探索
可以使用以下指令來執行測試探索:
python -m unittest discover
這個指令會自動搜尋當前目錄下所有符合 test_*.py
格式的測試檔案並執行。如果需要指定特定的目錄或檔案格式,可以使用以下選項:
python -m unittest discover -s tests -p "test_*.py"
這樣可以省去手動指定測試檔案的麻煩,使得在大型專案中管理測試變得更加高效。

7. 使用 unittest 提升測試效能的技巧
如果測試執行時間過長,可能會影響開發效率。以下是幾個使用 unittest
提高測試效能的方法。
優化檔案 I/O
需要讀寫檔案的測試可以透過在記憶體中執行來提高效能。例如,使用 StringIO
來模擬檔案操作,避免磁碟 I/O 延遲。
from io import StringIO
class TestFileOperations(unittest.TestCase):
def test_write_to_memory(self):
output = StringIO()
output.write('Hello, World!')
self.assertEqual(output.getvalue(), 'Hello, World!')
透過這種方式,可以有效提高測試的執行速度。
使用 Mock 來減少外部依賴
為了最小化對外部資源(如 API、資料庫)的存取,可以使用 Mock 來替代,以減少測試時間。例如,以下範例使用 Mock 來模擬 API 回應:
from unittest.mock import MagicMock
class TestApiCall(unittest.TestCase):
def test_api_response(self):
mock_api = MagicMock(return_value={'status': 'success'})
response = mock_api()
self.assertEqual(response['status'], 'success')
透過這種方式,可以避免不必要的網路或資料庫存取,進一步提升測試效能。
8. 總結與下一步
本文介紹了如何使用 Python 的 unittest
來進行單元測試,從基本概念到高級技巧,包括測試設定、Mock 依賴、效能優化等。
主要重點整理
- 基本使用方式: 繼承
unittest.TestCase
,並使用斷言方法來撰寫測試。 - setUp() / tearDown(): 在測試執行前後執行共用邏輯,提高程式碼可讀性與維護性。
- Mock 技術: 用於取代外部依賴,確保測試快速且穩定。
- 測試探索: 自動發現並執行測試,適用於大型專案。
- 效能優化技巧: 使用記憶體內部處理與 Mock 減少 I/O 操作,提高測試速度。
下一步
掌握 unittest
的基礎後,可以進一步學習進階測試技術,例如參數化測試(parametrized testing)來一次測試多組輸入,或使用測試覆蓋率工具來檢查測試涵蓋範圍。此外,也可以探索其他測試框架如 pytest
,根據專案需求選擇最適合的測試工具。
單元測試是開發的重要一環,透過測試可以更早發現錯誤並確保程式碼品質,因此應當積極導入並持續優化測試流程。