设为首页 加入收藏

TOP

Python单元测试:unit test code coverage
2019-02-11 14:55:47 】 浏览:58
Tags:Python 单元 测试 unit test code coverage

Python单元测试:unit testing best practices
Python单元测试:unit test code coverage

开发环境配置

单元测试覆盖率

  • unittest: Python built-in standard library
  • Pytest: a third party Python testing framework
  • Coverage.py:one of the most popular code coverage tools for Python
  • Pytest-cov:Python plugin to generate coverage reports. In addition to functionalities supported by coverage command, it also supports centralized and distributed testing
  • Nose可以将所有的单元测试文件一次全部执行,并且提供了coverage的插件,能够统计整体的覆盖率,官网有详细的使用介绍https://pypi.org/project/nose/
bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp$ pwd
/c/Users/bobho/Desktop/tmp

bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp$ dir
  app.py  test.py

bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp$ cat app.py
#!/usr/bin/env python

# -*- coding: utf-8 -*-

import sys

def process_input(a, b, operation):
    if operation == "add":
        return a + b
    if operation == "subtract":
        return a - b
    if operation == "multiple":
        return a * b
    if operation == "divide":
        if b == 0:
            return "Invalid input"
        return a / b

if __name__ == "__main__":

		    

print(process_input(int(sys.argv[1]), int(sys.argv[2]), sys.argv[3])) bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp $ cat app.py #!/usr/bin/env python # -*- coding: utf-8 -*- import sys def process_input(a, b, operation): if operation == "add": return a + b if operation == "subtract": return a - b if operation == "multiple": return a * b if operation == "divide": if b == 0: return "Invalid input" return a / b if __name__ == "__main__": print(process_input(int(sys.argv[1]), int(sys.argv[2]), sys.argv[3])) bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp $ python test.py test_0010_add (__main__.TestApp) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp $ pip3 install coverage Collecting coverage Downloading https://files.pythonhosted.org/packages/9c/c2/036ccdc0bbcef7d980dd f89c132b39c81b2ba645f1c904b0c8edc957f60a/coverage-4.5.2-cp36-cp36m-win_amd64.whl (183kB) Installing collected packages: coverage Successfully installed coverage-4.5.2 You are using pip version 9.0.3, however version 18.1 is available. You should consider upgrading via the 'python -m pip install --upgrade pip' comm and. bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp $ coverage run test.py test_0010_add (__main__.TestApp) ... ok ---------------------------------------------------------------------- Ran 1 test in 0.000s OK bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp $ coverage report Name Stmts Miss Cover ----------------------------- app.py 14 9 36% test.py 15 0 100% ----------------------------- TOTAL 29 9 69%

添加单元测试,更新后的test.py如下

import unittest

from app import process_input

class TestApp(unittest.TestCase):
    def setUp(self):
        self.a = 10
        self.b = 5

    def test_0010_add(self):
        result = process_input(self.a, self.b, "add")
        self.assertEqual(result, 15)

    def test_0020_subtract(self):
        result = process_input(self.a, self.b, "subtract")
        self.assertEqual(result, 5)


def suite():
    suite = unittest.TestSuite()
    suite.addTests(
        unittest.TestLoader().loadTestsFromTestCase(TestApp)
    )

    return suite


if __name__ == "__main__":
    unittest.TextTestRunner(verbosity=2).run(suite())

再次运行覆盖率检查,可以看到覆盖率已经提升

$ coverage run test.py
test_0010_add (__main__.TestApp) ... ok
test_0020_subtract (__main__.TestApp) ... ok

----------------------------------------------------------------------
Ran 2 tests in 0.000s

OK

bobho@LAPTOP-ET2KSKHR MINGW64 ~/Desktop/tmp
$ coverage report
Name      Stmts   Miss  Cover
-----------------------------
app.py       14      7    50%
test.py      18      0   100%
-----------------------------
TOTAL        32      7    78%

运行coverage html会在当前目录下面生成一个htmlcov,打开其中的app_py.html可以看到具体哪些行被覆盖到了

13918377-19b7f2b31bf00b1e.png
image.png

默认情况下,coverage生成的结果文件为.coverage,你可以通过修改环境变量COVERAGE_FILE来修改这个文件的后缀名。你也可以是用-a把多次运行的结果合并到一个文件里,否则,每次生成的结果文件都是上一次运行的结果。你可以是用coverage erase清空之前运行的结果文件。

coverage threshold

covearge可以使用参数--fail-under指定一个数字,当coverage的结果小于这个数字,coverage命令返回一个错误码2,但这个参数对annotate命令无效

$ coverage run run_my_tests.py 
... running all tests
$ coverage report --fail-under=100
... display the report
$ echo $
2

如果覆盖率不是100%,则返回值是2。也可以通过python api来验证覆盖率,示例如下:

cov = coverage.coverage(..)
cov.start()
ret = run_all_my_tests()
cov.stop()
if ret == 0:
    covered = cov.report()
    assert covered > 100, "Not enough coverage"
unittest框架

unittest 框架默认根据ASCII码的顺序加载测试用例,数字与字母的顺序为:09,AZ,a~z 如果要让某个测试用例先执行,不能使用默认的main()方法,需要通过TestSuite类的addTest()方法按照一定的顺序来加载

如果需要,用户可以自己实现discover(),遍历目录并添加和组合测试用例。利用discover获取指定目录或多级目录下的测试用例,但存放用例的目录属性必须是python package,必须要有init.py,不然不会获取成功


编程开发网
】【打印繁体】【投稿】【收藏】 【推荐】【举报】【评论】 【关闭】 【返回顶部
上一篇Python, C++ Comparision from AN.. 下一篇cmd中执行Python命令时>>&g..

评论

帐  号: 密码: (新用户注册)
验 证 码:
表  情:
内  容:

array(4) { ["type"]=> int(8) ["message"]=> string(24) "Undefined variable: jobs" ["file"]=> string(32) "/mnt/wp/cppentry/do/bencandy.php" ["line"]=> int(217) }