Python - doctest与unittest的区别

172

我正在尝试在Python中开始进行单元测试,想知道有人能否解释一下doctest和unittest的优缺点。

你会在什么条件下使用它们?

11个回答

194

两者都有价值。 我同时使用doctest和nose代替unittest。我使用doctest来测试一些在作为文档时有用的用法示例。通常,我不会将这些测试做得很全面,只是为了提供有用信息。实际上,我是在反向使用doctest:不是根据我的doctest检查代码是否正确,而是根据代码来检查文档是否正确。

原因是我发现全面的doctest会让文档显得混乱不堪,因此您最终要么得到无法使用的docstrings,要么得到不完整的测试结果。

对于实际测试代码,目标是彻底测试每一个情况,而不是通过示例说明它的功能,这是一个不同的目标,我认为可以通过其他框架更好地实现。


30
有很少的样板代码,我发现编写测试用例变得更加简单易懂。只需编写一个“test_foo()”函数并开始编写测试用例的启动成本也很低,这有助于抵制在明确测试用例之前就进行有趣代码部分的诱惑。 - Brian
你使用哪些其他的测试框架?还是只用 nose? - Joe
7
鉴于这个答案的年代久远,值得一提的是旧版本的unittest中很多“样板文件”已经基本消失了。我仍然更喜欢Nose,但它几乎没什么区别。 - Adam Parkin
我发现pytest经常被低估,所以我想在这里发表一下我的看法... 我偏爱pytest和doctest的组合。像Brian上面描述的那样使用doctest:用于说明和使文档可测试。使用pytest编写单元测试等。pytest作为测试运行器,因为它也可以运行doctests - floer32
我知道这篇文章有点老了,但是我想发表一下我的看法:我也使用nose已经有一段时间了,绝对推荐它而不是unittest。正如提到的那样,unittest仍然需要样板代码来识别测试的位置。而使用nose,我只需将其指向包含代码的目录,如果有一个以“Test”开头的文件,它就会认为它是一个测试。事实上,我只需要运行一个简单的批处理文件,运行“nosetests --with-coverage --cover-html --cover-html-dir=Tests\html --cover-erase --cover-package”,它也可以进行覆盖率测试。 - Sbspider
2
FYI,nose 已经处于“维护模式”数年,并且很可能会停止所有开发(除非有第三方干预)。它的维护者建议新项目使用替代工具。 - Six

50

我几乎专门使用unittest进行测试。

偶尔,我会在文档字符串中添加一些可以被doctest使用的内容。

95%的测试用例都是使用unittest编写的。

为什么这样做呢?因为我喜欢保持文档字符串尽可能简短明了。有时测试用例有助于澄清文档字符串。但大多数情况下,应用程序的测试用例太长了,不适合放在文档字符串里。


看到一个例子会很酷,你觉得哪些适合用 docstring 描述,哪些不适合。我其实很喜欢使用 docstring 来明确地展示如何使用接口,但是将其同时用于单元测试可能不太合适。 - user1767754

38

使用文档测试的另一个优点是您可以确保代码实际执行了文档所描述的功能。随着时间的推移,软件更改可能会使文档和代码执行不同的功能。 :-)


33

我是一名生物信息学家,我编写的大部分代码都是“一次性、一项任务”脚本,即仅需运行一两次并执行单个具体任务的代码。

在这种情况下,编写大型单元测试可能会过度,而文档测试是一个有用的折衷方案。它们更快速易写,并且由于通常被合并到代码中,它们允许始终关注代码应该如何行动,而不必打开另一个文件。在编写小脚本时非常有用。

此外,当您需要将脚本传递给不擅长编程的研究人员时,文档测试也很有用。有些人发现理解单元测试的结构非常困难;另一方面,文档测试是使用的简单示例,因此人们可以只需复制和粘贴它们以查看如何使用它们。

因此,总结我的答案:当您需要编写小型脚本,并需要将其传递给不是计算机科学家的研究人员时,文档测试是很有用的。


6
“当你需要编写小脚本并且需要将其传递或展示给非计算机科学研究人员时,doctest很有用。” 非常好的观点。我也这样做,非Python程序员总是惊讶于文档可以被执行。 - Daniel Canas

14

如果你刚开始接触单元测试,我建议从使用 doctest 开始,因为它非常简单易用。它还自然地提供了一定程度的文档。而对于更全面的 doctest 测试,你可以将测试放在一个外部文件中,这样就不会混淆你的文档。

如果你以前使用过 JUnit 或类似的东西,并想要以通常的方式编写单元测试,那么我建议使用 unittest


4
我曾被鼓励朝这个方向(首先是使用“doctest”)发展,但最终我感到后悔了。对于非琐碎的测试用例,我的编辑器失去了语法高亮和自动完成功能。当测试在单独的文件中时,我不能再从编辑器中直接运行测试 - 每次都需要切换回相应的源文件上下文。 - Oddthinking

8
我不使用 doctest 来替代 unittest。尽管它们有些重叠,但这两个模块的功能并不相同:
- 我使用 unittest 作为单元测试框架,它可以帮助我快速确定对代码的任何修改对其余代码的影响。 - 我使用 doctest 保证注释(即文档字符串)仍然与代码的当前版本相关。
test driven development 带来的广泛记录的好处我从 unittest 中获得。 doctest 解决了更为微妙的风险,即过时的注释会误导代码的维护。

7

我只使用unittest;我认为doctest会使主模块变得混乱。这可能与编写彻底的测试有关。


7

同时使用两种方法是有效而相当简单的选项。 doctest 模块提供了 DoctTestSuiteDocFileSuite 方法,分别从模块或文件创建一个与 unittest 兼容的测试套件。

因此,我会同时使用两者,并通常使用 doctest 进行对需要很少或无需设置(参数为简单类型)的函数进行简单测试。实际上,我认为一些 doctest 测试有助于记录函数,而不是削弱它的价值。

但对于更复杂的情况,以及更全面的测试用例集,我会使用提供更多控制和灵活性的 unittest。


4

我几乎从不使用doctest。我希望我的代码能够自我说明,而文档字符串则为用户提供文档。在我看来,将数百行测试代码添加到模块中会使文档字符串变得难以阅读。我还发现单元测试更容易进行修改。


4

Doctest有时会导致错误结果,特别是当输出包含转义序列时。例如:

def convert():
    """
    >>> convert()
    '\xe0\xa4\x95'
    """
    a = '\xe0\xa4\x95'
    return a
import doctest
doctest.testmod()

提供

**********************************************************************
File "hindi.py", line 3, in __main__.convert
Failed example:
    convert()
Expected:
    'क'
Got:
    '\xe0\xa4\x95'
**********************************************************************
1 items had failures:
   1 of   1 in __main__.convert
***Test Failed*** 1 failures. 

此外,它没有检查输出的类型。它只比较输出字符串。例如,它已经将一些类型变成了有理数,如果它是整数,则打印出来就像整数一样。然后假设您有一个返回有理数的函数。因此,doctest不能区分输出是有理数整数还是整数。


6
您可以使用原始文档字符串(r""" ... """)来解决第一个问题。 - icktoofay
在Python 3.4中运行良好。为了使其在Python 2.7中也能正常工作,请在您的文档字符串中使用'\\xe0\\xa4\\x95' - Cees Timmerman
我还发现,即使在文件顶部加上正确的“coding utf-8”注释行,unicode文字也不能在doctest中使用。通常情况下,doctest的支持不如unittest测试那么好,因此有些错误得不到修复。 - RichVel

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接