我觉得以前在我开发程序的时候,除了文档,可能单元测试是另外一个让我希望别人都写,但是自己又一点都不想写的东西。但是,随着开发程序的增多,以及自己对 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. 关于jQuery.click()函数

    最近接手了前同事的项目,关于使用线程控制实现代码热插拔功能! 在线程中,使用了ChatWebSocketHandler,与前台进行实时交互,今天我拿到需求是这样的,结合chatWebSocketHan ...

  2. 粗略整理的java面试题

    1.垃圾回收  是回收的空闲堆空间 只有在cpu空闲并且堆空间不足的情况下才回收 2.threadlocal  就是为线程的变量都提供了一个副本,每个线程运行都只是在更新这个副本. Threadloc ...

  3. .Net 上传图片之前获取图片的宽高

    Stream st = Request.Files[0].InputStream;                  Byte[] buffer = new Byte[st.Length];      ...

  4. [java基础] java中的自动装箱与自动拆箱

    自动装箱的一个例子: Integer i = 1; //实际上是执行了Integer i = Integer.valueOf(1) 自动拆箱的一个例子: Integer a =1; int b = a ...

  5. NOIP2017衢二中旅游记Day 1

    NOIP前一天下午早早的去了衢州: 车程大概在4个半小时左右: 车上大家都一脸颓废,并混杂着动听的音乐: 到了衢州二中,立刻跑去吃晚饭: 吃饭的队伍特别长,吃面的却空无一人: 我毅然决然地选择了去吃面 ...

  6. 微信小程序入门(前言)

    最近接到一个开发微信小程序的任务,由于没有开发过小程序,所以只能查看官方文档.查找相关博文.资料来开发. 微信小程序一开始出现就受到热烈的追捧,因为其"无需安装.用完即走"的理念确 ...

  7. [转载] FreeMarker教程

    转载自http://www.blogjava.net/freeman1984/archive/2010/11/04/337239.html FreeMarker是一个模板引擎,一个基于模板生成文本输出 ...

  8. ZedBoard开发板学习记录(一)之开发环境的搭建(Ubuntu16.04)以及运行HelloWorld程序的测试

    ZedBoard开发板由PL和PS两大部分组成, 对PS操作,一般有两个办法: (1).在Windows系统上面,使用SDK新建C Project SDK自带编译环境,编译后自动产生elf文件.使用U ...

  9. Nytro MegaRaid

    Nytro MegaRaid简介 Dell R720xd,内存64G ,12块 SAS Dell R510xd,内存48G ,12块 SAS   SSD+SAS   SSD对于用户透明   raid会 ...

  10. 这应该是目前最快速有效的ASP.NET Core学习方式(视频)

    ASP.NET Core都2.0了,它的普及还是不太好.作为一个.NET的老司机,我觉得.NET Core给我带来了很多的乐趣.Linux, Docker, CloudNative,MicroServ ...