Python单元测试最佳实践
Are you ready?
↓↓↓
今天的课程为《 Python单元测试》,内容共分为三个部分:单元测试的概念、工具与方法、Coverage 统计单元测试覆盖率的工具和Mock 简化单元测试的工具。
单元测试的概念、工具与方法
单元测试的概念
测试具有许多种不同的类型,比如说单元测试、模块测试、联调测试、系统测试、交付测试等。在这些测试之中,单元测试是最先要完成的。单元测试通常是由开发者去完成,用来验证代码中的函数是否符合预期。因此,它聚焦于函数的逻辑以及核心的算法是否正确。通常而言,一个单元测试用例是用于判断在某个特定条件或场景下,某个特定函数的行为。
单元测试的意义
单元测试的意义包括两个方面。
(1)质量
①单元测试主要针对函数,颗粒度小、测试针对性强,bug更容易暴露;
②由于单元测试覆盖面较窄,无需考虑其它函数或者所依赖的模块,所以它的场景易构造,核心功能验证更充分;
③进行单元测试保证整体代码结构良好,使代码就具有较高的可测性和可维护性。
(2)效率
单元测试能够提高开发效率,主要表现在:
①单元测试进行的时间较早,测试场景构建快,可有效减少调试时间。
②由于单元测试只针对修改的代码展开测试,无需考虑额外内容,所以在较短时间内即可把预期的逻辑测试充分。
③单元测试能够在项目开发初期发现的bug,bug发现的时间越早,所带来的收益越大。由于尽早发现bug能够节省整个项目开发的时间,所以单元测试可加快开发效率,缩短开发周期。
单元测试框架
(1)测试框架选择
在进行单元测试的时候,我们需要测试框架作为工具。一个良好的测试框架能够让测试工作事半功倍,此处我们介绍三个框架。
①Unittest是Python标准库中原生自带的,它的好处在于无兼容性问题,是其他框架的基础;不足之处在于编码略显繁琐,入门门槛稍高。
②Pytest的好处在于编码简洁、生态好、插件丰富、使用人数多;不足之处在于他属于第三方库,使用前另需提前安装。
③Nose2能够兼容Unittest,也属于第三方库,需要安装,但是与Pytest相比,它迭代缓慢,使用人数少。
在这里我们选择Unittest作为单元测试的框架,原因有二:首先,作为Python标准库中原生自带的框架,Unittest无兼容性问题;其次,第三方库难以保证长期快速迭代,易过时。
(2)Unitest的基础概念
在做单元测试之前,需要先了解一下Unittest的几个基础概念。
①Test(测试用例),针对一个特定场景,特定目的具体测试过程。
比如说一个函数通过一组输入测试它,就是一个测试用例;如果一个函数通过三组输入来测试,即为三个测试用例。
②TestCase(测试类),可以包含同一个测试对象的多个测试用例。
如果一个函数通过三组输入来测试,也就是三个测试用例,这三个测试用例可以合成为一个测试类。
③TestSuite(测试集),可以包含多个测试类的多个测试用例。
④Assertion(断言),必须使用断言判断测试结果。
⑤TestFixture,为测试做统一的准备和清除工作,通常是初始化,连接数据库,准备数据,断开数据库,清除现场等。
扩展来说,TestFixture有四种最常使用的作用范围,分别为:
→ setUp:在测试类的每个测试用例执行前执行。
→ teardown:在测试类的每个测试用例执行后执行。
→ setUpClass:在测试类的第一个测试用例执行前执行。
→ tearDownClass:在测试类的最后一个测试用例执行后执行。
TestFixture可以让单元测试代码更简单,但并非必须使用,也不要求配对出现。
单元测试的规范
想要做好单元测试,必须遵循一定的规范。下面介绍一下单元测试涉及的规范。
(1)所有的单元测试必须使用断言(assert)判断结果,禁止出现无断言的测试用例;
使用断言,不但有利于他人理解,而且一旦出现不符合预期的情况,可以立即找出问题。
可以使用assertEqual, assertNotEqual 来判断相等或不相等,assertTrue,assertFalse 来判断Boolean, assertRaises 判断抛出的异常是否符合预期。
(2)测试用例需要具有自表述能力,达到见名知意。
比如命名test_login_with_invalid_password(),通过它的名字便可知它是用一个非法的密码去测试登录功能,具有自表述能力;但是如果命名为 test_login_case_(),名字减少了很多信息,难以得知它具体在做什么,不具有自表述能力。
(3)测试用例之间相互独立,不应相互依赖、相互调用。
(4)一个测试用例只测一个函数。一个测试用例里面可以包含这一个函数的多个场景,但不能包含有多个参数的函数。原因在于,复杂测试用例出现错误时,无法定位问题的出处。
单元测试对编码的要求
单元测试中代码需保持一致性,尽量不要出现结果不一致的情况。假设有的代码会带来不一致性,导致单元测试无法稳定运行。针对这种情况,有两种解决方案:第一,将带来不一致性的代码抽取出来,把它作为一种变量传入我们需要调用或使用一致性变量的时候;第二,借助第三部分即将讲到的一个工具——mock——来解决这种问题。
Coverage 统计 单元测试覆盖率的工具
单元测试做完之后如何评价我们单元测试的效果。此时需要用到覆盖率工具,即Coverage。Coverage是一个第三方的工具,需要提前下载安装。
(1)统计覆盖率方法
把python替换为coverage run-branch,然后会生成coverage文件,文件里会记录所有我们需要的覆盖率信息。
(2)打印覆盖率信息
执行coverage report-m 命令,读取当前目录下.coverage文件,打印覆盖率信息。输出Stmts(总行数), Miss(未覆盖行数), Branch(总分支数), BrPart (未覆盖分支数), Cover(覆盖率) , Missing(未覆盖具体信息)等信息。
(3)覆盖率中排除某些文件
执行coverage report-m—omit=file 1[,file 2,……] 命令, 在统计并打印覆盖率时,排除某些文件。若有多个文件用逗号分隔。
(4)生成HTML格式的覆盖率信息
针对代码量较大,查找覆盖率信息难度较大、耗时较长的情况,执行coverage html [–omit=file1[,file2,……]]命令,将覆盖率信息以html格式显示。
Mock 简化单元测试的工具
使用mock工具的原因与其功能
Mock基于实际进行单元测试的场景而产生,以下三类场景非常具有代表性:
①构造模块。需要测试模块A,但它要调用的模块B还未开发,可是测试却不容推迟、需按时进行,面对这种情况,我们可以使用Mock生成一个还未写完的代码,即可进行相应的测试。
②改变函数逻辑。代码中含有结果不可预知的代码,例如time.time()(时间), random.random()(随机数)。Mock可以改变含有结果不可预知代码的函数的逻辑,强行让其返回我们想要的返回值,使其结果可预知。
③减少依赖。在所有模块代码都已完成,但无法保证代码稳定性的情况下。针对其他模块的质量不可靠的情况,可通过Mock工具构造一个相对稳定的模块,从而规避其他模块的问题。
Mock使用场景
通过以下10个场景来讲述Mock的常见用法。
场景01:通过 return_value,Mock可以强行修改,永远返回我们想要的返回值,支持的类型包括string,number,Boolean,list,dict等。
场景02:将前一个例子的实例名改为类名,可实现替换类方法的返回值。
场景03:通过 side_effect,根据调用次数返回想要的结果,当超出调用次数时抛StopIteration 异常。
场景04:通过 side_effect可以完全修改函数的逻辑,使用另一个函数来替换它,根据参数返回想要的结果。
场景05:通过 side_effect抛出想要的异常或错误。
场景06:针对需要mock在特定要求下生效的情况,通过with.patch.object设定一个作用域以达到限制mock作用域的目的。
场景07:获取调用信息,如函数是否被调用、函数被调用的次数、函数被调用的形式、函数调用的参数等。
场景08:通过create_autospec在返回值改变的同时,确保api不会因mock而改变。
场景09:针对需要调用的函数、调用的接口完全没有开发的情况,可以通过Mock从零构造依赖模块从而完成测试。
场景10 :替换函数调用链。比如说用popen去执行一个命令,然后用read函数把它读取出来,再用split去做切分,这就是一个函数调用链(os.popen(cmd).read().split())。
Mock 对编码的要求
在模块引入方式上,推荐以import XXX的形式引入,以XXX.func()形式调用,不要from.xxx import *,因为需要一个链条指向它,否则无法达到我们的预期。
关于Python单元测试
我们今天就讲解到这啦
点击进入获得更多技术信息~~
Python单元测试最佳实践相关推荐
- 领域驱动设计之单元测试最佳实践(二)
领域驱动设计之单元测试最佳实践(一) 介绍完了DDD案例,我们终于可以进入主题了,本方案的测试代码基于Xunit编写,断言组件采用了FluentAssertions,类似的组件还有Shouldly.另 ...
- @sql 单元测试_SQL单元测试最佳实践
@sql 单元测试 SQL unit testing is a testing method which allows us to test the smallest, atomic programm ...
- vim写python_用 Vim 写 Python 的最佳实践
先来晒个图: 对于一些 Python 的小项目,使用 vim 是一个不错的选择.本文内容整理自我在知乎的回答 用 Vim 写 Python 的最佳实践是什么?,下面的内容是对知乎旧有回答的一个补充,尤 ...
- 30个python的最佳实践,快去试试吧!
30 个 Python 的最佳实践.小贴士和技巧 原:作者 | Erik-Jan van Baaren 原:译者 | 弯月,责编 | 屠敏 以下为译文: 1. Python 版本 在此想提醒各位:自2 ...
- 30 个 Python 的最佳实践、小贴士和技巧
作者 | Erik-Jan van Baaren 译者 | 弯月,责编 | 屠敏 出品 | CSDN(ID:CSDNnews) 以下为译文: 元旦过完了,我们都纷纷回到了各自的工作岗位.新的一年新气象 ...
- Virtualenv or Anaconda?Python虚拟环境最佳实践
最近同时在Window和Linux上交替使用Virtualenv和Anaconda,期间一直在思考两种工具哪一个更好?是否可以统一使用其中一个完成所有Python项目的环境构建?针对这个问题,本文做了 ...
- python编码最佳实践之总结
2019独角兽企业重金招聘Python工程师标准>>> 相信用python的同学不少,本人也一直对python情有独钟,毫无疑问python作为一门解释性动态语言没有那些编译型语言高 ...
- Junit内部解密之四: Junit单元测试最佳实践
我们做使用Junit工具来做单页测试或接口测试时,需要注意一些问题,包括我们的编码规范,test规范,以及编写测试代码的策略,以下个人的总结. 1.为还没有实现的测试代码抛出一个异常.这就避免了该测试 ...
- 30 个 Python 的最佳实践、小贴士和技巧,不可错过哟!
1. Python 版本 在此想提醒各位:自2020年1月1日起,Python 官方不再支持 Python 2.本文中的很多示例只能在 Python 3 中运行.如果你仍在使用 Python 2.7, ...
最新文章
- 使用Ext Form自动绑定Html中的Form元素
- (七)渐变 矩形渐变 放射渐变
- C语言学习笔记(一)_hello world
- Codeforces Round #700 (Div. 2) D1 D2. Painting the Array 思维
- android 技能标签功能_iOS和Android用户体验设计差异
- drbd(三):drbd的状态说明
- arm-hisiv100nptl-linux-gcc编译boa和移植
- wincc怎么做数据库_关于WINCC通过PLCSIM来进行仿真中要怎么设置?
- [原创]Datagrid和Button控件
- python 官方 中文 文档
- cpp设计并实现大整数
- 重温张欣穗购书衷心与申霞艳,张鸿等名师座谈《千万与春住》二零一九年六月二十四日
- Ubuntu18.04之lightdm取代gdm
- can‘t connect to mysql server on localhost解决办法。 net start mysql——无法启动服务,原因可能是已被禁用或与其相关联的设备没有启动。
- CSUOJ1238--兵临城下
- 【自然语言处理】ChatGPT 相关核心算法
- Linux上可用的Markdown编辑器
- 【Android】打包生成APK教程
- MATLAB中的eig函数
- python 日历壁纸_Excel+Python=精美DIY壁纸日历
热门文章
- linux命令:java程序后台运行
- shell如果文件夹不存在则创建
- 使用docker-compose配置redis服务
- Ansible 介绍和架构、特性
- Hadoop存算分离实现方案探讨
- 【收藏】Hadoop解决Could not locate executable null\bin\winutils.exe in the Hadoop binaries.问题
- 【网址收藏】helm charts github地址
- idea安装golang插件(仅针对2017年之前的idea版本)
- springboot集成kafka及kafka web UI的使用
- Linux centos 6.7 设置主机名