Django 测试覆盖率与代码覆盖率
我成功安装并配置了django-nose
和coverage
。
问题是,当我只运行./manage.py shell
并退出这个shell时,它显示的代码覆盖率是37%。我明白执行的代码并不意味着已经测试过的代码。我的问题是——接下来该怎么办呢?
我想要的是在执行任何测试之前,能够导入所有的Python模块并“安定下来”,然后直接告诉coverage
:“好的,从这里开始计算代码覆盖率。”
理想情况下,这应该由nose
来完成,在执行每个测试套件之前,重置“被触及”的代码行。
我不知道该从哪里开始寻找或开发。我在网上搜索过,但没有找到有用的信息。任何帮助或指导都将非常感谢。
附言:
我尝试执行了类似这样的代码:
DJANGO_SETTINGS_MODULE=app.settings_dev coverage run app/tests/gme_test.py
它成功了(显示1%的覆盖率),但我不知道如何对整个应用程序做到这一点。
编辑:这是我的覆盖率配置:
[run]
source = .
branch = False
timid = True
[report]
show_missing = False
include = *.py
omit =
tests.py
*_test.py
*_tests.py
*/site-packages/*
*/migrations/*
[html]
title = Code Coverage
directory = local_coverage_report
4 个回答
我有点搞不清楚你想要达到什么目的。
关于Django的测试,这里有很详细的介绍:https://docs.djangoproject.com/en/dev/topics/testing/overview/
你可以在你的应用里写测试,文件名叫test.py。我觉得用nose没必要,因为Django自带的测试方式其实很简单。
然后你可以用这个命令来运行测试:coverage run ./manage.py test main
,其中'main'就是你的应用名。
你需要按照这里的说明来指定你的代码源文件:http://nedbatchelder.com/code/coverage/cmd.html,这样只有你的代码才会被计算在内。
比如,你可以这样运行:coverage run --source=main ./manage.py test main。
即使你只用简单的测试示例,还是会有一定的覆盖率。这是因为在启动服务器时,你的代码的某些部分会被执行,比如模块里的定义等等。
我也遇到过同样的问题。我通过创建一个 .coveragerc 文件来节省了一些时间,这个文件里指定了一些选项,和那个获得奖励的回答里提到的差不多。
现在我运行 'coverage run manage.py test' 然后再运行 'coverage report -m',就能看到覆盖率报告,以及哪些代码行没有被覆盖。
(关于 .coveragerc 文件的详细信息,可以查看这里: http://nedbatchelder.com/code/coverage/config.html)
“好的,开始在这里计算代码覆盖率。”这可以通过覆盖模块的API来实现。你可以在命令行中查看这个功能。直接引用自 http://nedbatchelder.com/code/coverage/api.html:
import coverage
cov = coverage.coverage()
cov.start()
# .. call your code ..
cov.stop()
cov.save()
cov.html_report()
你可以自己制作一个测试运行器,完全按照你的需求来做(有些人认为任何单元测试产生的覆盖率都是可以的,而另一些人则只接受由特定单元测试引起的单元的覆盖率)。
因为你使用了django-nose,所以你有两种方式来运行代码覆盖率测试。第一种方法已经被DaveB提到过了:
coverage run ./manage.py test myapp
上面的命令实际上是运行了覆盖率测试,它会监控测试命令执行的所有代码。
另外,django-nose包里默认包含了一个nose覆盖率插件(http://nose.readthedocs.org/en/latest/plugins/cover.html)。你可以这样使用它:
./manage.py test myapp --with-coverage
(还有一些额外的选项,比如哪些模块应该被覆盖,是否要生成HTML报告等等。这些都在上面的链接中有说明,你也可以输入./manage.py test --help
来获取一些快速信息。)
运行nose覆盖率插件会导致覆盖率测试在django启动代码执行之后才开始,因此相应的代码不会被报告为已覆盖。
当你以原来的方式运行覆盖率测试时,大部分报告为已覆盖的代码都是导入语句、类定义、类成员等。因为Python在导入时会评估这些代码,所以覆盖率自然会标记它们为已覆盖。然而,运行nose插件时,启动代码不会被报告为已覆盖,因为测试运行器是在django环境加载后才开始的。当然,这样的一个副作用就是你永远无法达到100%的覆盖率(……或者接近100% :)),因为你的全局作用域语句永远不会被覆盖。
经过反复切换和尝试覆盖率选项后,我现在使用覆盖率的方式是这样的:
coverage run --source=myapp,anotherapp --omit=*/migrations/* ./manage.py test
这样一来,
a. 覆盖率会将导入语句、类成员定义等标记为已覆盖(这其实是事实——这些代码已经成功导入并被解释了)
b. 它只会覆盖我的代码,而不会覆盖django的代码或我使用的任何其他第三方应用;覆盖率百分比将反映我的项目覆盖的情况。
希望这对你有帮助!