python unittest与(子)进程的覆盖率报告

时间:2014-12-08 17:12:54

标签: python python-3.x nose nosetests coverage.py

我正在使用nose来运行我的“unittest”测试,并nose-cov包含覆盖率报告。这些都可以正常工作,但我的部分测试需要将一些代码作为multiprocessing.Process运行。 nose-cov文档声明它可以multiprocessing,但我不确定如何使其发挥作用。

我只是通过运行nosetests并使用以下.coveragerc运行测试:

[run]
branch = True
parallel = True

[report]
# Regexes for lines to exclude from consideration
exclude_lines =
    # Have to re-enable the standard pragma
    pragma: no cover

    # Don't complain about missing debug-only code:
    def __repr__
    #if self\.debug

    # Don't complain if tests don't hit defensive assertion code:
    raise AssertionError
    raise NotImplementedError

    # Don't complain if non-runnable code isn't run:
    if 0:
    if __name__ == .__main__.:
    def __main__\(\):

omit =
    mainserver/tests/*

编辑:

我修复了我的“.coveragerc”文件中的parallel开关。我也尝试在我的site-packages目录中添加sitecustomize.py之类的内容:

import os
import coverage
os.environ['COVERAGE_PROCESS_START']='/sites/metrics_dev/.coveragerc'
coverage.process_startup()

我很确定它仍然无法正常工作,因为“缺失”报告仍显示我知道正在运行的行(它们输出到控制台)。我还尝试在运行测试用例之前在我的测试用例文件中添加环境变量,也在shell中添加环境变量。我还尝试在multiprocessing.Process调用的函数中显式调用相同的东西来启动新进程。

3 个答案:

答案 0 :(得分:1)

首先,您需要的配置设置为parallel,而不是parallel-mode。其次,您可能需要按照coverage.py文档的Measuring Subprocesses部分中的说明进行操作。

答案 1 :(得分:1)

另一件需要考虑的事情是,如果在运行coverage时看到多个覆盖文件。也许这只是后来将它们结合起来的问题。

答案 2 :(得分:1)

tl; dr —要使用coverage + nosetests +鼻子的--processes选项,请将coverage的--concurrency选项设置为multiprocessing ,最好是在.coveragercsetup.cfg中而不是在命令行中使用(另请参见:command line usageconfiguration files)。


长版...

我也为此花了一段时间,在信中遵循Configuring Python for sub-process coverage上的文档。最后,在重新仔细检查coverage run --help的输出时,我偶然发现了--concurrency=multiprocessing选项,这是我以前从未使用过的选项,它似乎是缺少的链接。 (事后看来,这是有道理的:鼻子的--processing选项在后台使用multiprocessing库。)

这是可以按预期工作的最小配置:


unit.py

def is_even(x):
    if x % 2 == 0:
        return True
    else:
        return False

test.py

import time
from unittest import TestCase

import unit


class TestIsEvenTrue(TestCase):
    def test_is_even_true(self):
        time.sleep(1)  # verify multiprocessing is being used
        self.assertTrue(unit.is_even(2))


# use a separate class to encourage nose to use a separate process for this
class TestIsEvenFalse(TestCase):
    def test_is_even_false(self):
        time.sleep(1)
        self.assertFalse(unit.is_even(1))

setup.cfg

[nosetests]
processes = 2
verbosity = 2

[coverage:run]
branch = True
concurrency = multiprocessing
parallel = True
source = unit

sitecustomize.py (注意:位于site-packages中)

import os
try:
    import coverage
    os.environ['COVERAGE_PROCESS_START'] = 'setup.cfg'
    coverage.process_startup()
except ImportError:
    pass

$ coverage run $(command -v nosetests)
test_is_even_false (test.TestIsEvenFalse) ... ok
test_is_even_true (test.TestIsEvenTrue) ... ok

----------------------------------------------------------------------
Ran 2 tests in 1.085s

OK

$ coverage combine && coverage report
Name      Stmts   Miss Branch BrPart  Cover
-------------------------------------------
unit.py       4      0      2      0   100%