我觉得以前在我开发程序的时候,除了文档,可能单元测试是另外一个让我希望别人都写,但是自己又一点都不想写的东西。但是,随着开发程序的增多,以及自己对 Bug 的修改的增多,我发现,UT 在很大程度上是对我有利的,虽然带来的结果就是可能我的 Dev 时间会增加 20-40% 左右,但是,相比较于一段时间之后突然冒出来一个 Bug,让你摸不着头脑;或者说突然一个接一个的 Bug 在你转测试之后提过来,写 UT 的幸福感和自豪感明显是更高的。

就我目前而言,我认为写单元测试有这么几个好处:

  1. 帮助减小代码的耦合度,这样你才能更容易得编写 UT
  2. 理清代码的模块依赖,这样你才能在 UT 中知道哪些东西要 Mock,哪些东西要 Stub
  3. 保持接口的干净和明朗,UT 就是针对接口编程,Input 和 Ouput 都需要明确
  4. UT 是一个自诠释的文档,别人可以通过你的 UT 来学习你的接口使用方式

这里我需要提出一点的就是,一般而言,我很难做到 Test First,也就是所谓的先完成 UT 代码的编写,然后再写实现代码。当然,这不是说不行,就以目前的经历来说,这做法欠妥,一个很重要的原因是项目周期的把控,如果你 UT First,万一后面你时间不够实现 Logical Code 了怎么办?光有 UT 并不能让你的整个 Project 跑起来。所以,一般来说,我经历的大部分项目都是先 Run 起来,然后再通过 UT 保证目前的功能是正常的,并且可以保证在以后的维护和更新中,功能的正确性不会被破坏。

测试方法

学过完善的软件工程体系的同学都知道,软件测试是软件工程中非常重要的一环,甚至于可以说对于一个 Project,测试人员的参与度比 Developer 的高多了,我刚毕业那会,测试人员的参与度可以说是贯穿了全流程,从需求的提出到验收发布,这整个流程都有测试人员的参与,而 Developer,可能参与到"转测试"环境就差不多完了,所以测试工程也是一项非常复杂的学科。

测试覆盖

因为测试非常复杂,所以也是有很多方法论和实践的。就拿 UT 来说,对于代码我们可以有几个不同的测试角度。例如覆盖角度来说,我们就有语句覆盖,分支覆盖,条件覆盖,路径覆盖和循环覆盖;测试内容来说,我们又会分模块测试,数据结构测试,路径测试,错误处理测试和边界测试等等。对于这么多测试,其实我发现大部分开源项目都没有很严格得遵守这些理论,因为可能说随便一条理论在实践中都能让人抓狂。

其实在我见过的几个流行的开源项目中,基本上都是以语句覆盖为目标进行的,并且并不能达到 100%,所以更多得是以主要功能是正常的为目标进行 UT 测试的。以下是部分开源项目的测试结果:

除此之外,对于 UT 的增加是在 issue 的基础上建立的,也就说当有用户提了一个 issue 之后,Maintener 觉得这个 issue 是个问题,并且会影响到我这个项目,那么就会开发开发相应的 patch fix 它,并且补上 UT,这种情况也是比较常见,这样的话,渐渐地 UT 的覆盖率也就慢慢上去了。

测试方法

在测试中,我们的代码可能会有很多依赖,例如模块依赖,组件依赖等等,为了解决这些依赖,我们总要有一些方法来处理,这里就有两项经常使用的技术:Stub 和 Mock。

我以前喜欢说讲一个对象 Mock 掉,意思就是讲一个对象用自定义的模拟类替换掉,从而让我们可以自定义类的行为和输出,但是,我发现这其实在测试中是 Stub,所谓的 Stub 就是模拟测试代码调用的模块和组件,从而自定义被调用后的行为和输出;而相比之下,Mock 的功能是验证模板或者组件有没有被调用,很常见的例子就是邮件发送服务有没有被调用,有没有输出日志内容等等。关于 Stub 和 Mock 更多的内容介绍我推荐 Martin Folwer 的这篇文章:Mocks Aren't Stubs

测试工具

在 Python 中,自身就带了类 XUnit 的 unittest 框架,使用也很简单,例如下面就是一个很简单的测试用例:

其实使用起来已经很简单了,但是 Python 的小伙伴还是嫌他又啰嗦又慢,所以你会发现 pytest 这个库很受欢迎。

pytest

pytest 作为一个单元测试框架,使用方法有多种,既可以和 python 自带的 unittest 类似,又可以很简单得就一个函数来写 UT;不仅开发效率会更高,而且执行效率也可以更高,其他优点就不啰嗦介绍了,官网里面都罗列了:pytest

至于有多简单方便,你将下面这段代码保存到 test_sample.py 文件中,然后在对应的目录路径下执行 pytest 命令

执行之后你应该会发现:

对,你会发现,就这么简单得执行起来了。但是,很多同学还是不满于此,因为很多 Python 项目不仅仅适应于一个版本的 Python,所以就会有多一个 Python 版本的测试(Python 的又一坑,2.6/2.7/3.x/3.5 不兼容)。

tox

为了满足一个 Python 项目可以在多个 Python 版本中可以正常运行,很多人会使用 tox 进行不同环境下的兼容性测试,所以 tox 的功能就是环境管理和测试运行。关于 tox 的更多功能使用和细则可以参考一下 tox 官网:Tox

tox 一般都会有一个 tox.ini 文件,例如一个简单的例子:

然后执行 tox 命令行工具就可以了,它就会找你机器上的各种环境,然后测试起来,最后的结果就有点类似于:

小结

单元测试是一种习惯,也是一种责任。通过单元测试,我们可以告诉别人我的代码是 Work 的,同时也给别人一种信任感,可以让别人相信你写的代码。同时,编写单元测试也是一项比较繁琐的事情,我们要处理依赖,考虑 Test Case,但是,这些过程都可以帮助我们更好得思考我们的项目和软件,从而让软件的结构和代码的质量提升一个台阶。

从开源项目看 Python 单元测试的更多相关文章

  1. 从开源项目看python代码注释

    最近看了不少代码,也写了不少代码,所以在看和写之间发现了很多的问题,真的是很多,至少从我的认识来看,有几个地方有很大的改进空间,这里不准备把所有的问题都列举出来,所以就先挑选一个比较明显得来和大家聊聊 ...

  2. GitHub 上适合新手的开源项目(Python 篇)

    作者:HelloGitHub-卤蛋 随着 Python 语言的流行,越来越多的人加入到了 Python 的大家庭中.为什么这么多人学 Python ?我要喊出那句话了:"人生苦短,我用 Py ...

  3. Python:渗透测试开源项目

    Python:渗透测试开源项目[源码值得精读] sql注入工具:sqlmap DNS安全监测:DNSRecon 暴力破解测试工具:patator XSS漏洞利用工具:XSSer Web服务器压力测试工 ...

  4. 讲解开源项目:用 Python 生成有“灵魂”的二维码

    本文作者:HelloGitHub-LITTLECHIEH 这是 HelloGitHub 推出的<讲解开源项目>系列,今天给大家推荐一个 Python 开源生成二维码的项目--qrcode ...

  5. Github上的python开源项目

    Python开源项目,期待大家和我们一起共同维护 github排名榜单 https://github.com/trending github搜索榜单:https://github.com/search ...

  6. 教你阅读Python开源项目代码

    为什么要阅读开源代码 阅读 Python 开源项目代码主要有如下三个原因: 在工作过程中遇到一些问题 Google 和 StackOverFlow 等网站找不到解决办法,只能去翻源码. 对某些项目或者 ...

  7. Python优秀开源项目Rich源码解析

    这篇文章对优秀的开源项目Rich的源码进行解析,OMG,盘他.为什么建议阅读源码,有两个原因,第一,单纯学语言很难在实践中灵活应用,通过阅读源码可以看到每个知识点的运用场景,印象会更深,以后写代码的时 ...

  8. 【Java经验分享篇01】小白如何开始学会看开源项目?

    目录 前言 1.理解开源 1.1.什么是开源? 1.2.开源的定义 1.2.1.开源软件优点 1.2.2.经典开源软件案例 1.3.关于开源协议 1.3.1.如何选择开源协议 2.如何查找开源项目 2 ...

  9. GTest Google的一种白盒单元测试框架 开源项目

    GTest为google开源的白盒单元测试跨平台测试框架,含丰富的断言.类型参数化测试.死亡测试.以及其他的测试选项设置.文件保存等,以下将对该项目C++的实现进行简要的分析,作为学习记录备份. 基本 ...

随机推荐

  1. Python通过跳板机链接MySQL的一种方法

  2. 网页静态化技术Freemarker的详细介绍

    网页静态化技术Freemarker 一.Freemarker的基本介绍 1.1为什么要使用网页静态化技术 网页静态化解决方案在实际开发中运用比较多,例如新闻网站,门户网站中的新闻频道或者是文章类的频道 ...

  3. 用大白话扯扯那"神奇"的面向对象编程思维(一)

    前言: 每当提到面向对象的时候,初学者肯定都是一脸懵逼的状态,到底什么是面向对象?会用面向对象后有什么牛逼之处吗?不会用是不是就会死掉?答案肯定不会死掉,我们可以来简单的举一 个栗子 1.当你想到熊猫 ...

  4. Maven 编译错误 Dynamic Web Module 3.0 requires Java 1.6 or newer 解决方案

    Eclipse Maven 开发一个 jee 项目时,编译时遇到以下错误:Description Resource Path Location TypeDynamic Web Module 3.0 r ...

  5. Redis轻快入门

    Redis是一个开源的使用ANSI C语言编写.支持网络.可基于内存亦可持久化的日志型.Key-Value数据库,并提供多种语言的API.从2010年3月15日起,Redis的开发工作由VMware主 ...

  6. Python的__init__.py用法

    python中包的引入,对于大型项目中都会使用到这个功能,把实现不同功能的python文件放在一起,组成不同lib库,然后在其他地方调用. 包,python源文件+__init__.py 模块,pyt ...

  7. RabbitMQ之路由

    为了实现一个新功能:只订阅消息的一个子集,例如只需要把严重的错误日志信息写入日志文件(存储到磁盘上),但同时仍然把所有的日志信息输出到控制台中. 绑定(Bindings) 创建绑定 channel.q ...

  8. Python——正则表达式特殊符号及用法

    由于正则表达式的内容比较多,所以单独写成一系列文章,主要内容是根据小甲鱼所讲的内容综合一下正则表达式的笔记. 贴上小甲鱼的<Python3 如何优雅地使用正则表达式>系列可观看的博客地址: ...

  9. PL/SQL 游标 (实验七)

    PL/SQL 游标 emp.dept 目标表结构及数据 要求 基于部门表建立游标dept_cursor1,使用记录变量接收游标数据,输出部门表信息: 显示格式: 部 门 号: XXX 部门名称: XX ...

  10. 在没有DOM操作的日子里,我是怎么熬过来的(中)

    前言 继上篇推送之后,在掘金.segmentfault.简书.博客园等平台上迅速收到了不俗的反馈,大部分网友都留言说感同身受,还有不少网友追问中篇何时更新.于是,闰土顺应呼声,在这个凛冽的寒冬早晨,将 ...