繁体   English   中英

pytest-cov如何报告由于pexpect.spawn而执行的python代码的覆盖范围?

[英]How can pytest-cov report coverage of python code that is executed as a result of pexpect.spawn?

我有一个Python项目,它使用pytest-cov进行单元测试和代码覆盖率测量。

我的项目的目录结构是:

rift-python
+- rift                        # The package under test
|  +- __init__.py
|  +- __main__.py
|  +- cli_listen_handler.py
|  +- cli_session_handler.py
|  +- table.py
|  +- ...lots more...
+- tests                       # The tests 
|  +- test_table.py
|  +- test_sys_2n_l0_l1.py
|  +- ...more...
+- README.md
+- .travis.yml
+- ...

我使用Travis为每次签入运行pytest --cov=rift tests ,并使用codecov查看代码覆盖率结果。

正在测试的软件包提供了一个命令行界面(CLI),它从stdin读取命令并在stdout上生成输出。 它是以python rift开头的。

tests目录包含两种类型的测试。

第一种类型的测试是测试单个类的传统单元测试。 例如,测试test_table.py导入table.py,并执行传统的pytest测试(使用断言等)。代码覆盖率测量按预期用于这些测试:codecov准确报告rift包中的哪些行已被或未被测试。

# test_table.py (codecov works)

import table

def test_simple_table():
    tab = table.Table()
    tab.add_row(['Animal', 'Legs'])
    tab.add_rows([['Ant', 6]])
    ...
    tab_str = tab.to_string()
    assert (tab_str == "+--------+------+\n"
                       "| Animal | Legs |\n"
                       "+--------+------+\n"
                       "| Ant    | 6    |\n"
                       "+--------+------+\n"
                       ...
                       "+--------+------+\n")

第二种类型的测试使用pexpect:它使用pexpect.spawn("python rift")来启动rift包。 然后使用pexpect.sendline将命令注入CLI(stdin),并使用pexpect.expect检查CLI(stdout)上命令的输出。 测试功能正常,但codecov没有报告这些测试的代码覆盖率。

# test_sys_2n_l0_l1.py (codecov does not pick up coverage of rift package)
# Greatly simplified example

import pexpect

def test_basic():
    rift = pexpect.spawn("python rift")
    rift.sendline("cli command")
    rift.expect("expected output")  # Throws exception if expected output not seen

问题:如何使用pexpect进行代码覆盖率测量以报告生成的rift包中的第二类测试的覆盖线?

注意:我省略了几个我认为不相关的细节,完整源代码在https://github.com/brunorijsman/rift-python (更新:此repo现在包含答案中建议的工作解决方案)

使用coverage run来运行pexpect程序并收集数据:

如果你经常这样做:

pexpect.spawn("python rift")

然后做:

pexpect.spawn("coverage run rift.py")

来源

经过测试,您可能希望将pexpect结果与“常规”单元测试结果结合起来。 coverage.py可以将多个文件合并为一个用于报告。

一旦创建了许多这些文件,就可以将它们全部复制到一个目录中,并使用combine命令将它们组合成一个.coverage数据文件:

$ coverage combine

来源

测试的另外两个细节:

  • 在本例中的测试程序(test_sys_2n_l0_l1.py)中,您必须确保在终止pexpect spawn和终止测试本身的那一刻之间有一个延迟。 否则,coverage将没有时间将结果写入.coverage。 我加了一个睡眠(1.0)。

  • 使用“coverage run --parallel-mode rift”。 这需要(a)确保.coverage不被后来的运行覆盖,(b)使“覆盖结合”工作(由“pytest --cov”自动运行)

您基本上必须启用子进程覆盖率跟踪

我建议使用https://pypi.org/project/coverage_enable_subprocess/轻松启用此功能。

建议/需要使用parallel = 1 ,然后必须导出COVERAGE_PROCESS_START ,例如export COVERAGE_PROCESS_START="$PWD/.coveragerc"

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM