前面的章节我们完成了任务管理主要功能的开发及单元测试编写,可如何知道单元测试效果怎么样呢?测试充分吗?还有没有没有测到的地方呢?

  本章节我们介绍一个统计测试代码覆盖率的利器Coverage,Coverage.py (以下简称 Coverage)是 Python 测试界最为流行的一个库之一,用来统计测试覆盖率。测试覆盖率可以从一个角度衡量代码的质量,覆盖率越高,说明测试越充分,代码出现 bug 的几率相对也就越小。当然需要明确的是,测试覆盖率仅仅只是衡量代码质量的一个角度,即是否有代码未经过单元测试验证,不能说100% 的覆盖率的代码就没有 bug 了。

1.1. 安装coverage

  IDE Python环境管理里或进入命令行安装coverage,如下图:

1.2. 运行coverage

1.2.1. 工程目录下运行coverage run manage.py test

D:\my tfs\IndDemo>coverage run manage.py test

Creating test database for alias 'default'...

System check identified no issues (0 silenced).

.............

----------------------------------------------------------------------

Ran 13 tests in 0.146s

OK

Destroying test database for alias 'default'...

D:\my tfs\IndDemo>

1.2.2. 查看统计结果coverage report

D:\my tfs\IndDemo>coverage report

Name                                                               Stmts   Miss  Cover

--------------------------------------------------------------------------------------

C:\Users\FQ\AppData\Roaming\Python\Python36\site-packages\six.py     490    242    51%

Collector\__init__.py                                                  0      0   100%

Collector\admin.py                                                     1      0   100%

Collector\migrations\__init__.py                                       0      0   100%

Collector\models.py                                                    1      0   100%

Collector\tests.py                                                     8      0   100%

Collector\views.py                                                    93     72    23%

IndDemo\__init__.py                                                    0      0   100%

IndDemo\settings.py                                                   21      0   100%

IndDemo\urls.py                                                        9      0   100%

Task\TaskBiz.py                                                       27      5    81%

Task\__init__.py                                                       1      0   100%

Task\admin.py                                                         82     36    56%

Task\apps.py                                                           4      0   100%

Task\migrations\0001_initial.py                                        7      0   100%

Task\migrations\0002_auto_20210314_0840.py                             6      0   100%

Task\migrations\__init__.py                                            0      0   100%

Task\models.py                                                        81     12    85%

Task\tests.py                                                         78      0   100%

Task\urls.py                                                           3      0   100%

Task\views.py                                                         33      2    94%

TestStringMethods.py                                                   9      1    89%

app\__init__.py                                                        0      0   100%

app\forms.py                                                           6      0   100%

app\migrations\__init__.py                                             0      0   100%

app\models.py                                                          1      0   100%

app\tests.py                                                          16      0   100%

app\views.py                                                          12      0   100%

manage.py                                                             10      2    80%

--------------------------------------------------------------------------------------

TOTAL                                                                999    372    63%

D:\my tfs\IndDemo>

1.2.3. coverage html命令获得更加详细的信息

  此命令在同级目录下生成包含html文件的文件夹,默认名称为htmlcov,点击打开index.html即可。

  通过覆盖率统计,我们可以看到Task\views.py文件的代码覆盖率94%,有两行代码未被测试覆盖到,就可以通过点击相关链接查看详情,如下图:

  有两行代码未被单元测试覆盖到,红色标注出来了非常方便查看未被覆盖额代码。

1.3. 修改单元测试代码

  接下来我们增加单元测试代码,增加 self.client.get('/task/1/change/')测试get请求才能进入到上图标红的代码分支。

...

    def test_task_change(self):
data={'source':'111','target':'05-01-11'}
#更新第一个task的源和目标值
response=self.client.post('/task/1/change/',data) model = Task.objects.get(pk=1)
self.assertEqual(model.Source,'111')
self.assertEqual(model.Target,'05-01-11') response=self.client.get('/task/')
self.assertIn('111',response.content.decode())
self.assertTemplateUsed(response,'Task/tasks.html') response=self.client.get('/task/1/change/')
self.assertIn('111',response.content.decode())
self.assertTemplateUsed(response,'Task/taskChange.html') 

  重新运行代码覆盖命令:

D:\my tfs\IndDemo>coverage run manage.py test

Creating test database for alias 'default'...

System check identified no issues (0 silenced).

.............

----------------------------------------------------------------------

Ran 13 tests in 0.212s

OK

Destroying test database for alias 'default'...

D:\my tfs\IndDemo>coverage html

  刷新网页/htmlcov/index.html,我们得到如下图:

  文件Task\views.py单元测试代码覆盖率达到了100%

1.4. 配置coverage

windows平台生成.coveragerc配置文件:

D:\my tfs\IndDemo>echo >.coveragerc

1.4.1. 基本配置

[run]

branch = True

source = .

[report]

show_missing = True

  • branch = True。是否统计条件语句的分支覆盖情况。if 条件语句中的判断通常有 True 和 False 两种情况,设置 branch = True 后,Coverage 会测量这两种情况是否都被测试到。
  • source = .。指定需统计的源代码目录,这里设置为当前目录(即项目根目录)。
  • show_missing = True。在生成的统计报告中显示未被测试覆盖到的代码行号。

  有一些文件其实并不需要测试,或者并非项目的核心文件(例如部署脚本 fabfile.py,django 的 migrations 文件等),这些文件应该从统计中排除。

  Coverage 默认显示全部文件的覆盖率统计结果,如果文件比较多的话就不好查找非 100% 覆盖率的文件。毕竟我们的目标是提高代码覆盖率,因此已达 100% 覆盖的代码文件我们不再关心。我们要做的是找到非 100% 覆盖率的文件,为其添加缺失的测试。

1.4.2. 完善配置

在 [run] 配置块中增加 omit 配置项可以指定排除统计的文件。

在 [report] 配置块中增加 skip_covered 配置项可以指定统计报告中不显示 100% 覆盖的文件。

[run]

branch = True

source = .

omit =

*/__init__.py

manage.py

IndDemo/*

*/migrations/*

IndDemo/wsgi.py

[report]

show_missing = True

skip_covered = True

重新运行覆盖率

D:\my tfs\IndDemo>coverage run manage.py test

Creating test database for alias 'default'...

System check identified no issues (0 silenced).

.............

----------------------------------------------------------------------

Ran 13 tests in 0.157s

OK

Destroying test database for alias 'default'...

D:\my tfs\IndDemo>coverage html

1.5. 小结

  通过单元测试的代码覆盖率coverage工具,我们能够快速的定位到那些代码未经过单元测试覆盖到,从而实现单元测试精准的定位,确保覆盖到所有代码。虽然说经过单元测试的代码就没有bug,没有经过单元测试的代码隐藏的可能的bug概率会高得多。所以企业开发过程中引入单元测试和覆盖率肯定会给项目开发质量带来一个飞跃的提升!

  这些都是深陷多个项目泥潭后,发现单元测试带来的好处。如果你和你团队也在做一个企业定制开发项目,组织编写单元测试吧,项目的中后期变更、扩展,你会发现编写单元测试的代价是多么的值得!

python工业互联网应用实战14——单元测试覆盖率的更多相关文章

  1. python工业互联网应用实战2—从需求开始

    前言:随着国家工业2025战略的推进,工业互联网发展将会提速,将迎来一个新的发展时期,越来越多的企业开始逐步的把产线自动化,去年年底投产的小米亦庄的智能工厂就是一个热议的新闻.小米/华为智能工厂只能说 ...

  2. python工业互联网应用实战3—模型层构建

    本章开始我们正式进入到实战项目开发过程,如何从需求分析获得的实体数据转到模型设计中来,变成Django项目中得模型层.当然,第一步还是在VS2019 IDE环境重创建一个工程项目,本文我们把工程名称命 ...

  3. python工业互联网应用实战1—SQL与ORM

    从sql到ORM应该说也是编程体系逐步演化的结果,通过类和对象更好的组织开个过程中遇到的各种业务问题,面向对象的解耦和内聚作为一套有效的方法论,对于复杂的企业应用而言确实能够解决实践过程中很多问题. ...

  4. python工业互联网应用实战7—业务层

    本章我们演示代码是如何"进化"的,实战的企业日常开发过程中,系统功能总伴随着业务的不断增加,早期简单的代码慢慢的越来越复杂,敏捷编程中的"禅"--简单设计.快速 ...

  5. python工业互联网应用实战13—基于selenium的功能测试

    本章节我们再来说说测试,单元测试和功能测试.单元测试我们在数据验证章节简单提过了,本章我们进一步如何用单元测试来测试view的功能代码:同时,也涉及一下基于selenium的功能测试做法.笔者过去的项 ...

  6. python工业互联网应用实战3—Django Admin列表

    Django Admin笔者使用下来可以说是Django框架的开发利器,业务model构建完成后,我们就能快速的构建一个增删查改的后台管理框架.对于大量的企业管理业务开发来说,可以快速的构建一个可发布 ...

  7. python工业互联网应用实战11—客户端UI

    这个章节我们将演示用户端界面的开发,当前演示界面还是采用先实现基本功能再逐步完善的"敏捷"模式.首先聚焦在功能逻辑方面实现普通用户与系统的交互,普通用户通过url能查看到当前任务的 ...

  8. python工业互联网应用实战15-前后端分离模式1

    我们在13章节里通过监控界面讲了如何使用jquery的动态加载数据写法,通过简单案例来说明了如何实现动态的刷新监控界面的数据,本章我们将演示如何从Django模板加载数据逐步演化到前后端分离的异步数据 ...

  9. python工业互联网应用实战18—前后端分离模式之jquery vs vue

    前面我们分三章来说明了使用django template与jquery的差别,通过jquery如何来实现前后端的分离,同时再9章节使用vue.js 我们浅尝辄止的介绍了JQuery到vue的切换,由于 ...

随机推荐

  1. windows回收站无法设置

    win+r运行 regedit HKEY_CURRENT_USER\Software\Microsoft\Windows\CurrentVersion\Policies\Explorer 修改NoRe ...

  2. 《C++反汇编与逆向分析技术揭秘》--算术运算和赋值

    一.加法 1.Debug下: 14: int nVarOne0 = 1 + 5 - 3 * 6;//编译时计算得到结果 00C0550E C7 45 F8 F4 FF FF FF mov dword ...

  3. JS中dom操作的事件

    Click--点击事件 优先级:dom.onclick 高于标签上的onClick属性 监听事件 --不会覆盖前面的事件效果 dom.addEventListener()    括号里面有三个参数 1 ...

  4. 单链表c语言实现的形式

    包括初始化,创建,查询,长度,删除,清空,销毁等操作 代码如下: #include<stdio.h> #include<stdlib.h> //定义单链表的数据类型 typed ...

  5. 深入理解Java并发框架AQS系列(四):共享锁(Shared Lock)

    深入理解Java并发框架AQS系列(一):线程 深入理解Java并发框架AQS系列(二):AQS框架简介及锁概念 深入理解Java并发框架AQS系列(三):独占锁(Exclusive Lock) 深入 ...

  6. day-03-基础数据类型

    基础数类型总览 10203 123 3340 int +- * / 等等 '今天吃了没?' str 存储少量的数据,+ *int 切片, 其他操作方法 True False bool 判断真假 [12 ...

  7. JavaScript深入理解-Promise以及常用方法详解

    Promise Promise 介绍 Promise 对象表示一个异步操作的最终完成(或失败)及其结果值. 状态: 一个 promise 必然处于以下几种状态之一 待定:初始状态(pending) 已 ...

  8. 承接上一篇,whale系统开篇,聊聊用户认证

    写在前面 上次老猫和大家说过想要开发一个系统,从简单的权限开始做起,有的网友表示还是挺支持的,但是有的网友嗤之以鼻,认为太简单了,不过也没事,简单归简单,主要的还是个人技术的一个整合和实战. 没错,系 ...

  9. python进阶(16)深入了解GIL锁(最详细)

    前言 python的使用者都知道Cpython解释器有一个弊端,真正执行时同一时间只会有一个线程执行,这是由于设计者当初设计的一个缺陷,里面有个叫GIL锁的,但他到底是什么?我们只知道因为他导致pyt ...

  10. Ancient Cipher UVA - 1339

      Ancient Roman empire had a strong government system with various departments, including a secret s ...