记录行为的测试断言
只有在记录预测和观察到的证据之后才允许协助。
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.