doctest通过扫描文档字符串中以>>>开头的交互式示例并执行比对来验证代码正确性,要求输出严格匹配REPL格式,支持ELLIPSIS等选项灵活处理动态内容。

doctest 能直接运行文档字符串里的 Python 交互示例,但必须严格匹配 REPL 输出格式,否则看似正确的代码也会失败。
doctest 识别哪些内容为测试用例
只扫描函数、类、模块的 __doc__ 字符串中形如 >>> 开头的行,紧随其后的 Python 表达式或语句会被执行;下一行如果是预期输出(不以 >>> 或 ... 开头),就参与比对。
-
>>>后必须有空格,>>>print(1)不被识别,正确写法是>>> print(1) - 多行语句用
...续行,且...后必须跟空格(... x = 1) - 输出比对区分空格、换行、引号类型(
'a'≠"a"),print()的换行也需显式写出 - 异常测试要写完整 traceback,从
Traceback (most recent call last):到异常类型和消息
运行 doctest 的三种常用方式
最轻量的是在模块末尾加 if __name__ == '__main__': doctest.testmod(),运行 python mymodule.py 即可;命令行方式更灵活:
-
python -m doctest mymodule.py:默认只报告失败,加-v显示全部结果 -
python -m doctest -o ELLIPSIS mymodule.py:启用ELLIPSIS选项,允许用...匹配任意子串(比如长 traceback 中间部分) -
python -m doctest -o NORMALIZE_WHITESPACE mymodule.py:忽略输出中多余的空格和换行差异(慎用,可能掩盖格式 bug)
常见失败原因与绕过技巧
最常踩的坑是浮点数精度、集合/字典顺序、对象内存地址等非确定性输出:
立即学习“Python免费学习笔记(深入)”;
- 浮点计算结果(如
0.1 + 0.2)建议用round(x, 10)或math.isclose(),不要直接写期望值0.30000000000000004 - 字典和集合在 Python 3.7+ 虽有序,但 doctest 里仍建议用
sorted(d.items())或转成list(d.keys())再断言 - 含
<__main__.X object at 0x...>的输出,用ELLIPSIS选项配合...替换地址段 - 时间相关输出(如
datetime.now())不适合写死,应改用固定时间戳或 mock
doctest 不适合测试什么
它不是单元测试替代品,而是文档验证工具。以下情况应换用 unittest 或 pytest:
- 需要 setup/teardown(如临时文件、数据库连接)
- 测试逻辑分支多、输入组合复杂,文档里写满示例反而干扰阅读
- 涉及 I/O、网络、外部依赖,稳定性差且难以复现
- 想做参数化测试(
@parameterized)或并发测试
真正有效的 doctest,是那些用户复制粘贴就能跑通的「活文档」——所以每一行都要经得起真实 REPL 检验,而不是为了通过测试而妥协输出格式。


















