![](/img/trans.png)
[英]How can I use pytest-cov to both generate a coverage report and also print to terminal?
[英]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.