doctest Soapbox
正如引言中提到的,doctest已经发展到三个主要用途:
- 检查文档字符串中的示例。
- 回归测试。
- 可执行文档/文字测试。
这些用途具有不同的要求,区分它们很重要。特别是,用不明确的测试用例填充文档字符串会导致错误的文档。
在编写文档字符串时,请小心选择文档字符串示例。有一个学问需要学习 - 起初可能并不自然。示例应该为文档增加真正的价值。一个很好的例子往往可以说很多话。如果谨慎处理,这些示例对您的用户来说将是非常宝贵的,并且会随着时间的推移和事情的变化而回报多次收集它们所需的时间。我仍然惊讶于我的一个doctest示例在“无害”更改后停止工作的频率。
Doctest也是回归测试的绝佳工具,特别是如果你不吝啬解释性文本。通过插入散文和例子,跟踪实际正在测试的内容以及为什么更容易。当一个测试失败时,好的散文可以使得更容易找出问题所在,以及应该如何解决问题。的确,您可以在基于代码的测试中编写大量的评论,但很少有程序员会这样做。许多人已经发现使用doctest方法会导致更清晰的测试。也许这只是因为doctest使编写散文比编写代码容易一些,而在代码中编写注释有点困难。我认为它比以上更深刻:编写基于doctest的测试时的自然态度是您想解释软件的优点,并用示例来说明它们。这反过来自然会导致以最简单的功能开始的测试文件,并在逻辑上进展到复杂性和边缘情况。一个连贯的叙述是结果,而不是一组孤立的函数,它们似乎随机地测试孤立的功能位。这是一种不同的态度,产生不同的结果,模糊了测试和解释之间的区别。
回归测试最好局限于专用对象或文件。有几种组织测试的选项:
- 将包含测试用例的文本文件编写为交互式示例,并使用testfile()或测试这些文件DocFileSuite()。这是推荐的,尽管对于从一开始就使用doctest设计的新项目来说,这是最容易做到的。
- 定义名为_regrtest_topic包含单个文档字符串的函数,其中包含指定主题的测试用例。这些功能可以包含在与模块相同的文件中,或者分离到单独的测试文件中。
- 定义__test__从回归测试主题到包含测试用例的文档字符串的字典映射。
当您将测试放入模块中时,模块本身可以成为测试运行者。当测试失败时,您可以安排测试运行者在调试问题时仅重新运行失败的doctest。这是一个这样的测试运行者的最小例子:
if __name__ == '__main__':
import doctest
flags = doctest.REPORT_NDIFF|doctest.REPORT_ONLY_FIRST_FAILURE
if len(sys.argv) > 1:
name = sys.argv[1]
if name in globals():
obj = globals()[name]
else:
obj = __test__[name]
doctest.run_docstring_examples(obj, globals(), name=name,
optionflags=flags)
else:
fail, total = doctest.testmod(optionflags=flags)
print("{} failures out of {} tests".format(fail, total))
脚注
不支持包含预期输出和异常的示例。试图猜测一个结束和另一个开始的地方太容易出错,这也会导致一个令人困惑的测试。
更多建议: