如何使用Django + Nose正确测试覆盖率

kap*_*nge 15 python django code-coverage django-nose

目前有一个项目配置为通过Django的管理命令运行覆盖,如下所示:

./manage.py test --with-coverage --cover-package=notify --cover-branches --cover-inclusive --cover-erase
Run Code Online (Sandbox Code Playgroud)

这会产生如下报告:

Name                        Stmts   Miss Branch BrMiss  Cover   Missing
--------------------------------------------------------------------------
notify.decorators               4      1      0      0    75%   4
notify.handlers                 6      1      2      0    88%   11
notify.notification_types      46     39      2      0    19%   8-55, 59, 62, 66
notify.notifications           51     51      0      0     0%   11-141
--------------------------------------------------------------------------
TOTAL                         107     92      4      0    17%   
Run Code Online (Sandbox Code Playgroud)

但是,这份报告存在问题.这是不对的.覆盖范围是标记线丢失,尽管它们确实被测试覆盖.例如,如果我通过nosetests而不是django的manage命令运行测试,我会得到以下正确的报告:

Name                        Stmts   Miss Branch BrMiss  Cover   Missing
-----------------------------------------------------------------------------
notify.decorators               4      0      0      0   100%   
notify.handlers                 6      0      2      0   100%   
notify.notification_types      46      0      2      0   100%   
notify.notifications           51     25      0      0    51%   13, 18, 23, 28, 33, 38, 43, 48, 53, 65, 70, 75, 80, 85, 90, 95, 100, 105, 110, 116, 121, 126, 131, 136, 141
-----------------------------------------------------------------------------
TOTAL                         107     25      4      0    77%   
Run Code Online (Sandbox Code Playgroud)

谷歌引导我进入了覆盖网站的常见问题解答,http://nedbatchelder.com/code/coverage/faq.html

问:为什么函数(或类)的主体显示为已执行,但def行不显示?

这是因为在定义函数后启动了coverage.定义行在没有覆盖测量的情况下执行,然后启动覆盖,然后调用该函数.这意味着身体被测量,但功能本身的定义不是.

要解决此问题,请提前开始报道.如果使用命令行以覆盖范围运行程序,则将监视整个程序.如果您使用的是API,则需要在导入定义函数的模块之前调用coverage.start().

问题是,我可以通过Django的manage命令正确运行覆盖率报告吗?或者我是否必须绕过管理以避免在执行"缺失"行后启动覆盖的情况?

iyn*_*iyn 14

目前,不可能准确地与django-nose一起运行覆盖(因为Django 1.7加载模型的方式).因此,要获取覆盖率统计信息,您需要直接从命令行使用coverage.py,例如:

$ coverage run --branch --source=app1,app2 ./manage.py test
$ coverage report
$ coverage html -d coverage-report
Run Code Online (Sandbox Code Playgroud)

您可以将coverage.py设置放入项目根目录中的.coveragerc文件(与manage.py相同的目录).

这个问题在django-nose GitHub页面上报道:https://github.com/django-nose/django-nose/issues/180所以维护人员知道这个问题,你可以让他们知道你也遇到了这个问题.

UPDATE

eliangcs指出(GiHub上的django-nose问题),woraround是修改你的manage.py:

import os
import sys

if __name__ == "__main__":
    # ...
    from django.core.management import execute_from_command_line

    is_testing = 'test' in sys.argv

    if is_testing:
        import coverage
        cov = coverage.coverage(source=['package1', 'package2'], omit=['*/tests/*'])
        cov.erase()
        cov.start()

    execute_from_command_line(sys.argv)

    if is_testing:
        cov.stop()
        cov.save()
        cov.report()
Run Code Online (Sandbox Code Playgroud)

它有效,但它是相当"hacky"的方法.

更新2

我建议每个使用鼻子的人看看py.test(http://pytest.org/),这是一个非常好的Python测试工具,它与Django很好地集成,有很多插件等等.我正在使用django-nose,但尝试了py.test并且从未回头.


Ned*_*der 5

正如文档所说,"使用命令行来运行覆盖范围的程序":

coverage run --branch --source=notify ./manage.py test
Run Code Online (Sandbox Code Playgroud)