单元测试就是一个软件中最小单元的测试,通常都是一个类或者方法
①软件的质量不是功能完整以及功能实现没有问题,而是实现功能的逻辑代码是否正确、是否健壮
②从测试环节的越晚发现问题,解决问题的成本就越高这个角度出发,如果问题能在单元测试阶段发现,这样可以极大的减少开发测试成本,提高开发测试效率
单元测试在测试过程中是比较重要的一环,但是也是很多团队缺失的一环,单元测试的意义是什么?单元测试的实施过程中会有怎样的坑?为什么一些团队没有单元测试呢?是由测试来做单元测试还是开发来做单元测试呢?
单元测试的定义及意义
首先是最经典的测试金字塔,其实针对测试金字塔有很多种搭建方式,例如:
这只是从测试金字塔角度去谈测试的方法,也可以说是测试的分类,当然如果是严格意义上的测试分类又有很多(例如以是否测试代码:黑盒,白盒,灰盒;是否运行:静态测试,动态测试等等)
单元测试是对软件中的最小单元进行测试和验证,通俗来讲就是代码中的一个函数或一个类,单元测试一定是白盒测试。
为什么提到测试金字塔,因为单元测试不仅是测试阶段的第一环,也是测试金字塔的基础,那代表着什么?
单元测试通常由开发工程师完成,一般会伴随开发代码一起递交至代码库。单元测试属于最严格的软件测试手段,是最接近代码底层实现的验证手段,可以在软件开发的早期以最小的成本保证局部代码的质量。另外,单元测试都是以自动化的方式执行,所以在大量回归测试的场景下更能带来高收益。同时,你还会发现,单元测试的实施过程还可以帮助开发工程师改善代码的设计与实现,并能在单元测试代码里提供函数的使用示例,因为单元测试的具体表现形式就是对函数以各种不同输入参数组合进行调用,这些调用方法构成了函数的使用说明。
如何做单元测试
要做好单元测试,首先要知道测试的对象是代码,代码的基本特征和逻辑,这样才能应用的相关的单元测试技术来进行单元测试case设计和进行测试。
要测试什么
单元测试是代码级别的测试,那么到底怎么测试代码。开发语言是多种多样的,客户端的Java,OC,swift,js等,服务端的Java,PHP,Python,Go等。先不提单元测试,代码级别的测试还有代码扫描,代码覆盖率的测试,可以找到一些定义好规则的代码漏洞或者代码规范方面的问题,那单元测试肯定做的就是除了这些之外的一些工作了。单元测试是对代码中的一个函数一个类的测试,那测试的是什么?
一个函数或者一个类包含什么,函数名(类名)、参数(属性/变量)、函数体(类中的各种方法)、返回结果,在函数的实现的中有各种循环、分支判断、函数调用,我们如果不管代码处理的是什么样的业务逻辑,仅看代码它就是在进行各种数据的处理,这也是为什么有的程序员会厌烦写业务,因为底层就是各种数据的增删改查,当然这其中根据业务还会有各种复杂的判断处理,并且也并不是所有的代码都是在做增删改查。
代码中的循环、每个分支判断、每个函数的输入输出都有可能产生缺陷,而单元测试的话就是测试这些函数(类)的功能输入输出、内部条件的判断。我们来看个例子(以开源项目httprunner为例,作者写了大量的单元测试)
在httprunner中loader类实现的功能是将yaml格式文件或者json格式文件亦或者存有两种格式文件的文件夹的接口测试case加载实现为程序中的case model,拿类中其中一个功能函数为例;
我们看到loader类实现将json格式的文件转换为testcase,然后进行断言是否加载成功,case中的每个字段是否能正确提取出来。
单元测试用例设计
无论是做功能测试,UI自动化测试,接口测试还是单元测试,都有一个很重要的东西那就是用例设计,用例设计体现了对代码对功能的理解程度,也一定程度上决定了测试功能覆盖,也会很明显的体现出软件质量。我从没觉得一个好的功能测试能比自动化测试能比接口测试差多少,自动化接口亦或者测试开发更多的是对于测试质量的点缀,无论是提高了效率还是丰富了测试技术来提高测试质量,这些工作都必须基于有很好的功能测试基础。
功能测试的用例设计是业务功能逻辑的输入输出,单元测试中就是函数的输入输出,那么单元测试中的输入输出有哪些呢?
输入:
输出:
了解了测试的输入输出,进行测试case设计就跟功能测试的用例设计差不多了,首先需要对上述可能产生的情况进行分类,也就是常用的case设计方法:等价类划分,然后针对不同分类的case再进行边界参数case设计,也就是边界值法。另外针对代码实现的逻辑应当根据产品业务逻辑进行预期的输入输出设计,而不能根据代码进行相关的设计,那就没什么用了。
再以httprunner为例,loader类加载csv文件,在加载时可能是一个参数,也可能是多个,因此需要进行两个或多个case设计
桩代码(stub)和mock
单元测试是测试软件的最小单元,它应该是与软件其他部分相分隔,例如与真实的数据库、网络环境等分隔开的,从而只测试我们关心的逻辑部分。那么对于有外部依赖的单元如何进行测试呢?这里提到两个概念:桩代码和mock
桩代码:用来代替真实代码的临时代码,对于依赖的其它部分直接使用固定代码或固定数据返回,属于完全模拟外部依赖
mock:这个就很常见了,它的作用也是替代真实的代码或者数据,与桩代码不同的是,mock还是可以进行相关的规则制定,还需要关心mock函数的调用和返回数据,例如mock的多次调用是否异常等等。mock用来模拟一些交互进行一些断言判断测试是否通过。
但是两者都是为了对被测试函数进行隔离和补齐。
在项目中如何进行单元测试
以上是单元测试的一些理论基础知识,那么如何在项目中应用单元测试。我认为单元测试的应用与自动化测试应用于项目应该是相同的考量。
基于上面的考虑,如何在项目中开展单元测试。
通常单元测试的框架选型以及配套的代码覆盖率工具的引入由开发架构师和测试架构师共同决定,并针对单元测试的一些细节进行相关的规范规定。
代码规范
单元测试的运用也需要一些规范支持,例如代码规范,注释规范,正是有这些规范的支持才能更好的进行单元测试,或者说没有这些规范很难进行单元测试。单元测试除了进行代码测试也为测试人员提供了很好的功能测试用例设计的逻辑参考,也为其它开发者熟悉代码提供了极大的便利。因此如果想让单元测试能做到这些功能就必须要能让别人看懂写的单元测试,或者写的代码,那这就要求需要有代码规范。而实际的工作中正因为缺少这样的规范或者开发没有时间去做到这些规范才导致了单元测试无法推动。那可以想想做哪些方面的规范:
1. 代码注释规范
2. 代码命名规范
3. 单元测试注释规范
4. 单元测试覆盖规范
5. 单元测试执行规范
规范这个问题也可以引申出一个问题,是由开发做单元测试,还是测试做单元测试,如果测试来做单元测试的话,需要掌握开发语言及框架,无论是前端的单元测试还是后端的单元测试,都需要熟悉相应的开发语言及相应的框架(开发框架,单元测试框架),只有熟悉这些才能进行合理的单元测试case设计和测试。
训练分类网络resnet18发生报错:RuntimeError: CUDA error: device-side assert triggered
一、chart.jschart.js是简单而灵活的javascript图表插件,底层封装了canvas,而且是复合目前主流的响应式。官网: http://www.chartjs.org1.创建一个简单的图表chart.js目前有两种版本1.0版本和2.0版本,两个版本创建图表的方式有区别。2.0版本该方式是2.0版本新增的方式。有4种方式获取<canvas>元素var ...
转:http://blog.csdn.net/pzasdq/article/details/52566973口水篇REST是设计风格而不是标准资源是由URI来指定。对资源的操作包括获取、创建、修改和删除资源这些操作正好对应HTTP协议提供的GET、POST、PUT和DELETE方法。通过操作资源的表现形式来操作资源。常用操作GET获取POST提交PUT更新Delete删除REST确实不是标准,只是...
Ubuntu VMwareTools 安装教程直接上图第一步第二步更改热键第三步 点击安装第四步 复制虚拟机中的 Tools文件到主文件夹粘贴同时按 Ctrl+Alt+F1 启动终端 Ctrl+Alt+F7(可以返回界面)输入ls 查看输入 tar -xzvf VMwareTools-10.3.10-13959562.tar.gz 回车即可解压 其实...
Foglight的Alarm Rule中有一类是 Event Driven事件驱动,可以用于将Foglight产生的报警统一发邮件,发短信,备份保存或转发到其他系统中。在使用该类报警规则时,会遇到发送两次报警问题,例如,假设我们创建一个Ping 某台网络设备的监控,当ping 不通时,产生一个常用的多级别报警,这时也将触发Event Driven 报警规则,这是符合我们要求的。接着,如果下一次pi...
1.valueStack分析1.valueStack分两部分:2.ognl分析: valueStack是ognl的一部分?1.三个要素: 1.上下文context (map结构)(存储数据), 2.root (arraylist结构)(存储数据) ,3.表达式 (取出数据) ;1.取出时加 '#' 是从context取数据2.取出时不加 '#' 是从root中取数据,从root中找...
算法老师留了三个作业给我们。额,因为他的题目写在黑板上,不能Copy,所以没抄了。不过,按照我意思的理解。他出的题目就是我这篇文章的题目吧。嗯嗯,根据老师的题目,我还是把题目意思写过来。 题目1 全排列 Description 输入正整数n,按字典序从小到大的顺序输出1~n的所有排列。 Input 输入一个正整数n(1 Output 输出前n个数的所有序列,序列之间的数字用空格隔开,每个序列占一行。 Sample I
接口框架swagger学习笔记
在t时刻:PID的控制规律为:假设是规定为直流电机调速的。输入量rin(t)为电机转速预定值(转/min)。输出量rout(t)为电机转速实际值(转/min)。偏差量为预定值和实际值之差(转/min)。执行器为直流电机。传感器为光电码盘(10线)。为了得到实际的转速。直流电机采用PWM调速转速,单位为转/min表示。问题一:通过PID环节后的u(t)是什么值?问题二:控制执行器(直流电机)转动转速应该为电压值(也就是PWM占空比)?问题三:u(t)与PWM之间存在怎样的联系?PID控制其实是
使用 SpringFox、Swagger2Markup、Spring-Restdoc和 Maven 构建 RESTful API文档。实现思路:1、先利用 SpringFox 库生成实时文档;2、再利用 Swagger2Markup,Maven插件生成 asciidoc文档;3、最后利用 asciidoctor Maven 插件生成 html 或 pdf ;运行环境: SpringBoot + ...
学习笔记,记录共享
PID算法公式可以在CSDN内查到,我只做了简单的PID运算,复杂的没有做,如下代码class PID:def init(self, kp, ki, kd, v):#类中所使用的任何变量都要在__init__方法内统一存放,如果在类的其他方法设置新的变量会出错print(“PID_init begin\n”)self.pid_kp = kpself.pid_ki = kiself.p...