記錄行為的測試斷言
只有在記錄預測和觀察到的證據之後才允許協助。
Prerequisites
完成上一個活動;如遇阻礙,使用列出的恢復連結。
Learning Objective
用 assertEqual 和 assertRaises 撰寫 unittest.TestCase,執行 python -m unittest -v,並解釋結尾的 OK 行證明了什麼、沒證明什麼。
Instructions
每個 test_ 方法是一條行為主張,名字應像文件一樣可讀,例如 test_empty_list_returns_zero。assertEqual(actual, expected) 檢查值;with self.assertRaises(例外型別): 證明呼叫按契約所說的方式失敗。執行測試有兩種方式。在專案目錄執行 python -m unittest -v(等同於 python -m unittest discover -v),會發現該目錄中名為 test_*.py 的模組。python test_counter.py 只透過檔案末尾的 unittest.main() 執行這一個檔案裡定義的測試;unittest.main() 不會發現旁邊的 test_*.py 模組。
Practice & Prediction Log
在空目錄中撰寫 counter.py,其中的 count_non_empty(lines) 回傳含有非空白字元的元素個數,元素不是 str 時拋出 TypeError。在 test_counter.py 中撰寫含四個測試的 CounterTests 類別:空列表回傳 0;純空白行被忽略;混合行只數非空行;非字串元素(例如 None)拋出 TypeError,用 assertRaises 檢查。先預測四個結果,再在該目錄執行 python -m unittest -v。Python 3.13/3.14 上的預期執行(測試按字母順序執行;耗時會變化;較舊的 Python 括號內的名字可能較短):
test_empty_list_returns_zero (test_counter.CounterTests.test_empty_list_returns_zero) ... ok
test_mixed_lines_count_only_non_empty (test_counter.CounterTests.test_mixed_lines_count_only_non_empty) ... ok
test_non_string_item_raises_type_error (test_counter.CounterTests.test_non_string_item_raises_type_error) ... ok
test_whitespace_only_line_is_ignored (test_counter.CounterTests.test_whitespace_only_line_is_ignored) ... ok
...
Ran 4 tests in 0.001s
OK
預測每個測試裡會執行哪條斷言。如果執行報告沒有測試被執行(Ran 0 tests),檢查檔案是否叫 test_*.py、以及發現命令的執行目錄是否正確。
參考實作(兩個檔案放在同一目錄;已用 Python 3.13 和 3.14 驗證):
# file: counter.py
def count_non_empty(lines):
"""Return how many items contain non-whitespace text.
Raise TypeError if an item is not a str.
"""
count = 0
for line in lines:
if not isinstance(line, str):
raise TypeError(f"expected str, got {type(line).__name__}")
if line.strip():
count += 1
return count
# end file
# file: test_counter.py
import unittest
from counter import count_non_empty
class CounterTests(unittest.TestCase):
def test_empty_list_returns_zero(self):
self.assertEqual(count_non_empty([]), 0)
def test_whitespace_only_line_is_ignored(self):
self.assertEqual(count_non_empty([" \t\n"]), 0)
def test_mixed_lines_count_only_non_empty(self):
self.assertEqual(count_non_empty(["alpha\n", " \n", "", "beta"]), 2)
def test_non_string_item_raises_type_error(self):
with self.assertRaises(TypeError):
count_non_empty(["alpha", None])
if __name__ == "__main__":
unittest.main()
# end file
在該目錄以發現方式執行:
$ python -m unittest -v
test_empty_list_returns_zero (test_counter.CounterTests.test_empty_list_returns_zero) ... ok
test_mixed_lines_count_only_non_empty (test_counter.CounterTests.test_mixed_lines_count_only_non_empty) ... ok
test_non_string_item_raises_type_error (test_counter.CounterTests.test_non_string_item_raises_type_error) ... ok
test_whitespace_only_line_is_ignored (test_counter.CounterTests.test_whitespace_only_line_is_ignored) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
直接執行檔案時,只會透過 unittest.main() 執行這個檔案裡的測試,模組顯示為 __main__:
$ python test_counter.py -v
test_empty_list_returns_zero (__main__.CounterTests.test_empty_list_returns_zero) ... ok
test_mixed_lines_count_only_non_empty (__main__.CounterTests.test_mixed_lines_count_only_non_empty) ... ok
test_non_string_item_raises_type_error (__main__.CounterTests.test_non_string_item_raises_type_error) ... ok
test_whitespace_only_line_is_ignored (__main__.CounterTests.test_whitespace_only_line_is_ignored) ... ok
----------------------------------------------------------------------
Ran 4 tests in 0.001s
OK
OK 證明了什麼:在這個直譯器上,這四個輸入的每條斷言都成立,包括 None 拋出了 TypeError。沒證明什麼:count_non_empty 對沒人測過的輸入(例如其他非 str 型別或少見的空白字元)也正確。
執行以 Ran 4 tests ... OK 結束且其中包含一個 assertRaises 測試,並能說明 OK 的含義是這些輸入下每條斷言都成立——而不是函式對所有可能輸入都正確。
Authoritative Source Resources & Provenance
Python Standard Library: unittest
對應章節 / 時間戳: Classes and functions: Test cases (TestCase assert methods)
驗證版本與日期: Python 3.12 documentation; verified 2026-10-30
Normative reference for unittest.TestCase, assertEqual, assertRaises, and python -m unittest output.
unittest ships with the interpreter, so every example runs offline; help(unittest.TestCase) documents the assert methods.
對比候選資源與選型分析 (2)
Strong third-party runner, but it adds an installation step and its own conventions; unittest needs no environment change and is the baseline the rest of the curriculum assumes.
Docstring-embedded examples suit tiny pure functions; unittest was selected for the structured TestCase isolation the check suites need.