Pytest 和覆盖率:为什么覆盖率结果因目录结构而异?

Dyl*_*non 5 django coverage.py pytest python-2.7

我有一个在相当大的 django 项目上使用 Pytest 的工作测试套件。问题是我无法使用覆盖率获得正确的结果,我想知道是否可能是因为项目目录结构。

考虑以下目录树示例:

.
??? apps
?   ??? api
?   ?   ??? __init__.py
?   ?   ??? tests
?   ?   ?   ??? __init__.py
?   ?   ?   ??? views
?   ?   ?       ??? __init__.py
?   ?   ?       ??? test_tickets.py
?   ?   ??? views
?   ?       ??? __init__.py
?   ?       ??? tickets.py
?   ??? support
?   ?   ??? __init__.py
?   ?   ??? tests
?   ?   ?   ??? __init__.py
?   ?   ?   ??? utils
?   ?   ?       ??? __init__.py
?   ?   ?       ??? test_management_commands.py
?   ?   ??? utils
?   ?   ?   ??? __init__.py
?   ?   ?   ??? management_commands.py
Run Code Online (Sandbox Code Playgroud)

以及覆盖率报告的示例输出:

coverage run --source apps/ -m py.test apps/
coverage report

Name                                        Stmts   Miss  Cover
---------------------------------------------------------------
apps/api/views/tickets.py                      42     18    57%
apps/support/utils/management_commands.py     135    100    26%    
Run Code Online (Sandbox Code Playgroud)

查看 html 报告,我可以看到测试执行的许多语句不被认为是覆盖的,即使它们应该被覆盖。我认为这个覆盖数据是不完整的,它似乎只考虑了导入、定义和文档字符串。

无法确定为什么覆盖率看起来不正确,我尝试运行一个测试模块,结果是肯定的:

coverage run --source apps/support/utils/management_commands.py -m py.test apps/support/tests/utils/test_management_commands.py
coverage report

Name                                        Stmts   Miss  Cover
---------------------------------------------------------------
apps/support/utils/management_commands.py     135     68    50%
Run Code Online (Sandbox Code Playgroud)

这更准确,HTML 报告显示我测试过的语句显示为这次涵盖。无法弄清楚为什么运行单个测试模块会产生准确的结果,我通过将测试移动到单个父文件夹下来修改目录结构。

.
??? apps
?   ??? api
?   ?   ??? __init__.py
?   ?   ??? views
?   ?       ??? __init__.py
?   ?       ??? tickets.py
?   ??? support
?   ?   ??? __init__.py
?   ?   ??? utils
?   ?   ?   ??? __init__.py
?   ?   ?   ??? management_commands.py
??? tests
?   ?   ??? __init__.py
?   ??? api
?   ?   ??? __init__.py
?   ?   ??? views
?   ?       ??? __init__.py
?   ?       ??? test_tickets.py
?   ??? support
?   ?   ??? __init__.py
?   ?   ??? utils
?   ?   ?   ??? __init__.py
?   ?   ?   ??? test_management_commands.py
Run Code Online (Sandbox Code Playgroud)

使用此目录结构重新运行覆盖率会产生更准确的结果:

coverage run --source apps/ -m py.test tests/
coverage report

Name                                        Stmts   Miss  Cover
---------------------------------------------------------------
apps/api/views/tickets.py                      42      0   100%
apps/support/utils/management_commands.py     135     68    50%
Run Code Online (Sandbox Code Playgroud)

谁能解释为什么在原始目录结构下使用 py.test 运行覆盖率会产生完全覆盖率?目录结构实际上是问题还是我在这里遗漏了其他东西?

附加信息:

# pytest.ini
[pytest]
addopts = --nomigrations
markers =
    slowtest: mark a test as being slow
    integration: mark a test as being an integration test

INSTALLED_APPS += ('django_coverage', )
TEST_DISCOVER_PATTERN = 'test_*'
COVERAGE_MODULE_EXCLUDES = [
    'settings',
    'urls$',
    'locale$',
    'tests$',
    'django',
    'migrations',
    'compressor',
    'templates?$',
    'fixtures$',
    'static$',
]
ROOT_PATH = os.path.abspath('%s/' % os.path.dirname(__file__))
Run Code Online (Sandbox Code Playgroud)

.coveragerc

[run]
source = apps
omit =
     apps/*/templates?/*
     apps/*/migrations/*
     apps/*/factories/*
     apps/*/tests/*
[html]
directory = coverage
Run Code Online (Sandbox Code Playgroud)

模块版本(有些可能无关):

pytest==2.9.0
pytest-cov==2.2.1
pytest-django==2.9.1
django-coverage==1.2.4
coverage==4.0.3
Run Code Online (Sandbox Code Playgroud)

Bla*_*g23 1

我发现我参加聚会有点晚了(3年前的问题,还没有被接受的答案),但因为我刚刚有同样的问题,有一个看似显而易见的答案coverage只会报告实际运行的代码。因此,如果您的测试没有调用一些代码,并且在应用程序的正常加载期间没有运行它,coverage则不会显示该代码的报告。不运行的代码不会导致错误:)