配色: 字号:
如何测试代码覆盖率:coverage
2016-08-18 | 阅:  转:  |  分享 
  
如何测试代码覆盖率:coverage.py简介

本文作者为MikeDriscoll,译者为linkcheng,校对EarlGrey,是Python翻译组完成的第二篇译文。本文为编程派微信公众号首发。



Coverage.py是一个用来测试代码覆盖率的Python第三方库。它起初是由NedBatchelder创建。在编程界,术语“覆盖”通常是用来描述测试的有效性,以及测试的实际覆盖率。coverage.py库支持Python2.6或者更高的版本,还兼容Python3的最新版以及PyPy。



pipinstallcoverage

执行以上指令来安装coverage.py,不过我们需要写一些代码才能使用它。创建一个名为mymath.py的模块,代码如下:



defadd(a,b):

returna+b





defsubtract(a,b):

returna-b





defmultiply(a,b):

returnab





defdivide(numerator,denominator):

returnfloat(numerator)/denominator

现在需要一个测试文件。接下来,我们创建一个测试add函数的测试文件,并将其命令为test_mymath.py。然后把它保存在与mymath.py的相同目录下。接着在测试文件中写入以下代码:



#test_mymath.py

importmymath

importunittest



classTestAdd(unittest.TestCase):

"""

Testtheaddfunctionfromthemymathlibrary

"""

deftest_add_integers(self):

"""

Testthattheadditionoftwointegersreturnsthecorrecttotal

"""

result=mymath.add(1,2)

self.assertEqual(result,3)

deftest_add_floats(self):

"""

Testthattheadditionoftwofloatsreturnsthecorrectresult

"""

result=mymath.add(10.5,2)

self.assertEqual(result,12.5)

deftest_add_strings(self):

"""

Testtheadditionoftwostringsreturnsthetwostringasone

concatenatedstring

"""

result=mymath.add(''abc'',''def'')

self.assertEqual(result,''abcdef'')





if__name__==''__main__'':

unittest.main()

一切准备就绪,让我们使用测试文件来运行coverage.py。打开终端并且进入我们刚才写的那两个文件所在的目录。然后通过以下方式执行coverage.py:



coverageruntest_mymath.py

注意,我们需要调用run才能让coverage.py运行指定的模块。如果模块接收参数,可以像正常运行这个的模块一样带上参数。当执行以上指令后,你会看到测试模块的输出,就像正常运行该模块一样。在当前目录下,你还会发现一个名字为.coverage的文件(注意开头的点号)。要想获得文件中的信息,需要执行以下指令:



coveragereport-m

执行这条指令将会在终端打印以下信息:



NameStmtsMissCoverMissing

----------------------------------------------

mymath.py9367%9,13,17

test_mymath.py140100%

----------------------------------------------

TOTAL

-m选项告诉coverage.py你想在输出信息中显示Missing列。如果省略-m选项,就只能看到前四列信息。上面的输出表明,coverage在执行完测试代码之后,判断我写的单体测试程序对mymath模块的覆盖率只有67%。“Missing”列表明哪些行代码没有被覆盖。如果你看过coverage.py指出的那些行代码,很快就会发现测试程序没有运行测试subtract,multiply和divide函数。



在尝试添加更多的覆盖率测试代码之前,先来学习一下怎么通过coverage.py来生成HTML报告。只需要执行以下命令即可:



coveragehtml

以上指令将会生成一个叫htmlcov的目录,其中包括各种各样的文件。进入这个目录,并通过浏览器打开index.html文件。在我的电脑上,浏览器加载了这样的页面:







实际上,你可以通过点击Module列中列出的文件名来打开一个新的页面,页面中将会明显标识出代码中没有被单体覆盖的部分。显然mymath.py的覆盖率不够高,所以点击mymath.py,页面最终显示如下:

以上截图清晰地展示了没有被单体测试所覆盖的部分。现在我们清楚地知道测试覆盖有哪些缺失了,接下来就给subtract函数添加单体测试,并且看一下覆盖率的改变。

打开test_mymath.py并且添加下边的类:

classTestSubtract(unittest.TestCase):

Testthesubtractfunctionfromthemymathlibrary

deftest_subtwww.wang027.comract_integers(self):

Testthemultiplyfunctionfrommymathlibrary

Testthatsubtractingintegersreturnsthecorrectresult

"""

result=mymath.subtract(10,8)

self.assertEqual(result,2)

现在我们需要重新对更新后的测试文件运行coverage。你只需要再次运行该命令即可:coverageruntest_mymath.py。命令输出将指出成功通过了四个测试。接着,重新运行coveragehtml,再打开index.html文件。你应该会看到我们达到了78%的覆盖率:

这次修改让覆盖率提高了11%!接下来,让我们给multiply和divide函数添加简单的测试,看覆盖率能否达到100%!

classTestMultiply(unittest.TestCase):

"""

Testthemultiplyfunctionfromthemymathlibrary

"""

deftest_subtract_integers(self):

"""

Testthatmultiplyingintegersreturnsthecorrectresult

"""

result=mymath.multiply(5,50)

self.assertEqual(result,250)

classTestDivide(unittest.TestCase):

"""

Testthedividefunctionfromthemymathlibrary

"""

deftest_divide_by_zero(self):

"""

Testthatmultiplyingintegersreturnsthecorrectresult

"""

withself.assertRaises(ZeroDivisionError):

result=mymath.divide(8,0)

再次运行之前运行过的命令,然后再重新打开“index.html”。然后就会看到如下截图:







正如你看到的那样,这次我们的覆盖率达到了100%!显然,覆盖率100%意味着我们测试程序测试了每一个需要被测试的函数。当然这也有些不尽人意的地方,比如:add函数的单体测试数量是其他几个函数的三倍,然而coverage.py并没有给出关于这些的详细信息。尽管coverage.py不能详尽说明我们是否测试了所有可能的参数组合情况,但却可以明确反映关于覆盖率的一些基本信息。



额外信息

顺便再简单提及一些coverage.py的其他特性。首先,coverage.py支持配置文件。配置文件格式是传统的“.ini”文件,使用中括号作为节与节的分界(例如:[my_section])。还可以使用#或者;(分号)来添加注释。



Coverage.py也允许在上述提到的配置文件中指定你需要解析的源文件。一旦在配置文件中设置了需要解析的文件,就可以通过运行coverage.py来看运行结果。它还支持“-source”命令行选项。最后,还可以使用“-include”和“-omit”选项来包含或者移除一个文件名模式的列表。这些选项也可以通过在配置文件中添加对应的配置项进行设置。



关于coverage.py想最后再说明一点,就是它支持插件。你可以自己写插件,也可以从网上下载并安装别人的插件来增强coverage.py的功能。



总结

现在你已经了解coverage.py的基本情况以及它的一些用途。Coverage.py可以检测单体测试代码并且发现单体测试覆盖中的漏洞。如果不确定你的单体测试程序是否达标,那么使用这个库包将会帮助你找到那些存在的漏洞。即便如此,你仍然需要认真负责地编写高质量的测试程序。如果没有写出有效的测试,而且测试还通过了,那么coverage.py也无法帮到你。

献花(0)
+1
(本文系thedust79首藏)