我有一个项目,该项目几乎具有完整的单元测试范围。只有一个声明没有涵盖,我无法找到一种好的方法。说这个项目叫做foo,我有foo / commands.py:

#!/usr/bin/python
[...]
def main(argv):
    [...]

if __name__ == '__main__':
    return main(sys.argv) # This line allegedly not covered by tests


我确实对此进行了测试! foo / tests / test_commands.py:

import unittest
class CommandsTest(unittest.TestCase):
    def test_direct_call(self):
        proc = subprocess.Popen(['python', 'foo/commands.py', 'help'], stdout=PIPE)
        stdout, stderr = proc.communicate()
        self.assertTrue(stdout.startswith('usage:'))
        self.assertEquals(0, proc.returncode)


(这不是我的实际测试,但是是按照这些原则进行的。)

我用鼻子作为我的测试跑步者:

nosetests --cover-erase --cover-tests --with-coverage --cover-package=foo -vs foo


问题是该特定语句不被视为“已覆盖”,因为我使用普通python而不是coverage.py(或python -coverage(在Ubuntu上称为)。我可以将其更改为python-coverage,但是我并不是真的想要这样做:


它可能不可用。
如果可用,则可能是命名不同。
如果有人想在没有覆盖内容的情况下运行测试套件就可以了。

现在,我有一个可怕的技巧:

interpreter = 'coverage' in sys.modules ['python-coverage', 'run'] or ['python']


并不是最易读的代码,但是想象一下使用更具可读性的方法的讽刺意味:

if 'coverage' in sys.modules:
    interpreter = ['python-coverage', 'run']
else:
    interpreter = ['python']


...只是意识到启用覆盖率时,“ else:”分支最终不会被调用,因此,我只有另一行单元测试无法执行的代码。

我的目标是使测试套件失败(如果存在)不是100%的覆盖率。我“需要” foo / commands.py中的语句,因为这是在开发过程中测试事物的非常方便的方法(在实际安装中,它将使用distutils console_scripts magic调用此文件)。

有想法吗?现有技术?有什么事吗?

注意:100%的覆盖率绝不能保证一切都很好。但是,不到100%可以保证您没有测试某些东西。我可以轻松地验证100%的覆盖率,因此我没有理由不这样做。

评论

如果没有100%的覆盖率,为什么您的目标是使测试套件失败? 100%的覆盖率能为您带来超过95%的覆盖率,但在更多关键区域进行更彻底的测试会带来什么好处?
100%的覆盖范围绝不能保证一切都很好。但是,不到100%可以保证您没有测试某些东西。我可以轻松地验证100%的覆盖率,因此我没有理由不这样做。

#1 楼

最简单的选择是将覆盖范围标记为忽略。您不仅仅知道coverage.py的功能,还可以从测量结果中删除该行:

if __name__ == '__main__':     # pragma: no cover
    return main(sys.argv) 


您还可以对Coverage.py使用一些技巧来达到目的在启动的子流程中测量代码。这听起来像是您真正想要的东西。

#2 楼

从.py文件中删除未发现的行,并使用

python -c "import foo; foo.main(args);"


您可以将其包装在别名或bash函数中。

#3 楼

解决方案1 ​​

将以下代码添加到您的测试运行器中:运行测试的入口点。)

import coverage
coverage.process_startup()


解决方案2

在项目的根目录中添加一个名为runtests.py的文件,其中包含以下内容内容:

#!/usr/bin/env python
import os
import sys
import pytest
import coverage


def main():
    coverage.process_startup()
    sys.path.insert(0, os.path.abspath('src'))
    return pytest.main()


if __name__ == '__main__':
    sys.exit(main())


解决方案3

在项目的根目录中添加一个名为.pth的文件,其内容如下:

import coverage; coverage.process_startup()