使用Python Coverage获取测试覆盖率


Coverage

当我们完成测试用例的编写之后,需要知道测试用例对整个代码的测试覆盖情况。此时可以使用Coverage工具运行测试用例并统计扫描结果。 在Python中,使用Coverage.py作为Coverage工具。Coverage可以执行测试用例,并生成HTML或者XML格式的报告。

安装

在控制台执行python -m coverage,如果有类似输出:

Code coverage for Python. Use 'coverage help' for help.

说明已经安装过。如果没有安装的话,可以执行: pip install coverage

就可以完成coverage的安装了。

测试代码和测试用例

待测试代码

code.py

def multiply(x, y):
    """
    将2个给定的参数相乘,并返回结果

    Args:
        :param x: 乘法算子x
        :param y: 乘法算子y
    Returns:
        x * y
    """

    if isinstance(x, int):
        return x * y
    else:
        return 0

测试用例代码

test.py

import unittest
from code import multiply


class TestMultiply(unittest.TestCase):

    def test_multiply_2_numbers(self):
        self.assertEqual(2, multiply(1, 2))

    def test_muliply_with_zero(self):
        self.assertEqual(0, multiply(1, 0))

    def test_multiply_with_char(self):
        self.assertEqual(0, multiply("a", 2))


if __name__ == "__main__":
    unittest.main()

Coverage的使用

完整的文档请参考: http://coverage.readthedocs.io/en/latest/cmd.html

或者使用help命令查看帮助信息: coverage help

常用的命令有:

coverage run & coverage report

coverage run 命令可以用来执行代码覆盖率统计,只需要通过coverage的run参数执行需要被统计的代码(测试用例)即可。例如: coverage run test.py arg1 arg2 ..

其中test.py是存放测试用例的文件。arg1, arg2这些是执行test.py需要用到的参数,如果不需要参数可以不传递。 测试用例执行完毕之后会生成一个覆盖率统计结果文件(data file),对应的文件名为 :.coverage。有了覆盖率统计结果的文件后,只需要再运行report命令,就可以看到统计的结果了,例如执行:coverage report会得到的结果:

Name      Stmts   Miss  Cover
-----------------------------
code.py       2      0   100%
test.py      16      0   100%
-----------------------------
TOTAL        18      0   100%

其中: Stmts表示语句总数。 Miss表示未执行到的语句数。

覆盖率就等于 (Stmts - Miss)/Stmts

coverage html

使用coverage html可以得到html格式的测试报告,命令如下:

coverage html -d coveragehtml

生成的报告会直接关联代码,并且支持高亮覆盖和未覆盖的代码,同时也支持排序。-d参数指定的是html文件所在的文件夹。生成的目录类似于:

➜  coveragehtml ls -l

code_py.html
coverage_html.js
index.html
jquery.ba-throttle-debounce.min.js
jquery.hotkeys.js
jquery.isonscreen.js
jquery.min.js
jquery.tablesorter.min.js
keybd_closed.png
keybd_open.png
status.json
style.css
test_py.html

可以在浏览器打开index.html来查看测试覆盖报告。

coverage combine

coverage combine是一个非常又用的命令,它可以将多份测试覆盖数据文件合并到一个目录里。比如我们的项目中有多个测试用例文件,我们就可以使用该命令将测试覆盖信息放到一个目录里,方便查看整个项目的测试覆盖率情况。 但是,需要注意的是,该命令对目录的结果文件名的格式是有要求的,需要合并的文件必须有同样的前缀,然后后面跟一个名称,然后再跟一个数字(通常是进行号),例如: .coverage.AAA.12345.4566

为了方便将执行结果进行合并,可以在执行统计时,在run参数后面跟一个 -p 参数。它会自动生成符合合并条件的结果文件。例如执行:

coverage run test.py -p

会得到如下结果的一个文件名:

.coverage.seraphln-ubuntu18.23345.830671

coverage run --branch

如果想统计分支覆盖率,可以在run后面添加 --branch参数。这样的话,在结果时会看到分支覆盖率的统计信息。

➜  coverage report
Name      Stmts   Miss Branch BrPart  Cover
-------------------------------------------
code.py       4      0      2      0   100%
test.py      16      2      2      1    83%
-------------------------------------------
TOTAL        20      2      4      1    88%

其中: Branch表示分支数 BrPart表示未执行到的分支数

coverage run --parallel-mode

如果代码是多进程的,比如一些web程序,想查看被测试代码中子进程的覆盖率,那就需要 --parallel-mode这个参数。

获取web程序的覆盖率

单元测试

web程序中的单元测试是使用web开发框架提供的client客户端来进行模拟HTTP请求。在Django和Flask中都有client的实现,使用Coverage获取它的测试覆盖率结果跟普通的单元测试的方法是一样的。

E2E test

E2E test是指端到端的测试,是用来模拟用户进行正常操作的测试。常见的e2e测试的流程为:服务端开启一个Web服务,客户端通过HTTP请求来进行测试。 此时想获取端上的覆盖率也可以使用Coverage。这是因为Coverage在实现上使用了atexit模块注册了一个回调函数,在Python退出时将内存中的覆盖率结果写到文件中。被测试脚本只有正常推出或者以 SIGINT 2信号退出才能触发atexit。才能得到测试覆盖率结果。

注意: CTRL + C触发的就是SIGINT 2信号,所以在e2e test执行完毕之后,使用CTRL + C就可以得到测试覆盖率文件了。