使用doctest、覆盖率与并发的Python测试探索

10

...还有一匹小马!不开玩笑,我正在寻找一种“只需运行即可”的测试组织方法。大多数东西都可以工作,但不是所有的部分都能配合得好。这是我想要的:

  • 自动发现测试,包括文档测试。请注意,文档测试的总和不能出现在单个测试中(即不是py.test --doctest-modules的方式)。
  • 能够并行运行测试。(类似于xdist的py.test -n)
  • 生成覆盖率报告。
  • 使 python setup.py test 只需要运行即可。

我的当前方法涉及到一个 tests 目录和 load_tests 协议。其中所有文件的名称都像 test_*.py。如果我创建一个名为 test_doctests.py 的文件,并使用以下内容,则可以使 python -m unittest discover 运行:

import doctest
import mymodule1, mymodule2
def load_tests(loader, tests, ignore):
    tests.addTests(doctest.DocTestSuite(mymodule1))
    tests.addTests(doctest.DocTestSuite(mymodule2))
    return tests

这种方法的好处是可以使用setuptools并提供setup(test_suite="unittest2.collector")

然而,这种方法有一些问题:

  • coverage.py需要运行一个脚本。因此,在这里我不能使用unittest2发现。
  • py.test不运行load_tests函数,因此它无法找到doctest和--doctest-modules选项很烂。
  • nosetests运行load_tests函数,但不提供任何参数。在nose的一侧,这似乎完全失效了。

如何改善这些问题或解决上述问题?


很好,你的问题正是我在寻找的答案。 :-) 关于coverage.py:使用“coverage -m unittest2 discover”应该可以工作(至少对于Py2.7中的“unittest”是这样)。 - Søren Løvborg
2个回答

2

这是一个老问题,但对于我们中的一些人仍然存在问题!我刚刚解决了它,并找到了与kaapstorm类似但输出更好的解决方案。我使用py.test来运行它,但我认为它应该与测试运行器兼容:

import doctest
from mypackage import mymodule

def test_doctest():
    results = doctest.testmod(mymodule)
    if results.failed:
        raise Exception(results)

如果失败,我最终得到的是标准输出(stdout)的打印内容,这与手动运行doctest时得到的一致,并且还有一个额外的异常信息,如下所示:

Exception: TestResults(failed=1, attempted=21)

正如kaapstrom所提到的,它不能正确计算测试(除非有失败),但我发现只要覆盖率数字高,这并不值得太多关注 :)

1

我使用nose,在遇到相同问题时发现了你的问题。

最终我采用的方法不是很好看,但确实可以运行测试。

import doctest
import mymodule1, mymodule2

def test_mymodule1():
    assert doctest.testmod(mymodule1, raise_on_error=True)

def test_mymodule2():
    assert doctest.testmod(mymodule2, raise_on_error=True)

不幸的是,它将模块中的所有文档测试作为单个测试运行。但是如果出现问题,至少我知道从哪里开始查找。失败会导致DocTestFailure,并附有有用的消息:

DocTestFailure: <DocTest mymodule1.myfunc from /path/to/mymodule1.py:63 (4 examples)>

虽然它可以与nose一起使用,但失败消息现在是完全的垃圾。在我看来,这只是超出了有用的范畴。我认为这个解决方案比提出的替代方案要差。 - Helmut Grohne

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