开发者学堂课程【ALPD 云架构师系列-云原生 DevOps36计:基于持续测试的质量守护:分层测试、测试自动化、单元测试(二)】学习笔记,与课程紧密联系,让用户快速学习知识。
课程地址:https://developer.aliyun.com/learning/course/82/detail/1290
基于持续测试的质量守护:分层测试、测试自动化、单元测试(二)
内容介绍
一、基于持续测试的质量守护
二、整体测试策略
三、质量与成本之间的平衡
四、质量的成本
五、分层测试-平衡质量与成本
六、发布过程
七、测试自动化
八、自动化测试的分层
九、测试自动化用例的反模式检查清单
十、测试自动化落地建议
十一、基于(预防)成本考量的单元测试选择性的策略
七、测试自动化
通过测试自动化的方式,如果要保证质量,需要获得高质量的成本,需要有一些相应的验证成本去投入。用测试自动化其实是有成本的,在原来的测试成本之上又多了一个成本,叫测试自动化的成本。
这个成本的目的其实是为了降成本,是为了降低验证成本。如果测试自动化写完就使用一两次,显然是不合理的。
测试自动化基本的思想是另一种形式的开发活动。一直有各种争议,做的不好的是不将其作为开发活动看待,不像一个软件一样做各种架构、各种考量、质量的设计,最后导致测试自动化变成手工测试的自动化。只是简单的将其翻译过来,用工具将其翻译为自动化是什么样子。实际这并不是划等号的过程。
上面给了四个方面:
1、不是所有的场景都适合自动化的。
自动化是做过筛选和取舍的,有些场景只能够通过自动化运行,并发或者特殊的场景需要构造特殊的数据,这样通过手工是非常难测的。
2、测试自动化是分层的。
并不是一层,并不是所有的东西都平铺直叙的,不是所有的东西放在一起就可以运行。
3、测试自动化是准确的。
不论是用力还是结果,还是给出的判断都应该是准确的而不是这个测试结果大概率是失败的,失败率是95%。这样的判断是没有意义的,剩下的5%还是需要通过人去判断。
八、自动化测试的分层
测试自动化分层可以从不同的角度去看。
1、从实现的角度来看:测试自动化本身至少分两类:一类是测试用到的相关资源。例如:library、resource文件、工具、数据都可以作为资源;另外一个是用例的实现本身,测试面向的是用户的业务或者场景。在做用例的划分也是需要描述业务和场景的,业务和场景本生就是有分层的。测试自动化相对一般的只简简单单把步骤自动化上面的区别是什么呢?最大的区别在于是有层级的,是由setup、setdown的,有一个说实话的阶段以及清理回收的阶段。
2、从需求方面来看:测试自动化不是需要将左右的用例、需求都实现,它本身就是分层的。例如最基础的内层就是基本功能。假设是做一个用户认证的,那么至少要让用户登录。第二个是扩展需求,在用户登录的基础上可能会有不同的认证方式。比如os等各种认证方式。再往上可能会有长尾的需求,比如某一些特殊的很少用的方式。所以从优先级来说先满足基础的需求,再去做扩展需求,最后做长尾的需求。
3、按结果做分层:同时做测试认证是准确的,执行完成后会给出准确的结果。这个结果能够判断出这个软件的质量达到了什么样的级别。比如所有的基础需求都验证过了,认为可以满足 QL-1的级别,那么可以告诉这次级别验证之后是 QL-1的级别。如果所有的长尾需求都验证完了,到了 QL-5.所以是按照结果做的分层。
九、测试自动化用例的反模式检查清单
看一下常见的反模,用例大家都在写。要把测试自动化当作另一种的研发活动来看待,作为一个用例研发反模会有哪些呢?上图是从一个分布好的检查工具中抽出来的。
1、首先整个的结构名称不合理,可能用例步骤描述不了一个明确的场景。
2、结构不合理。测试中间步骤特别少,比如说只有一个步骤,那么这个测试到底是什么呢?是不明确的。
3、危险的测试步骤。可能其中的某一步使用 crash 的,整个测试进程 crash 的,那就会导致看不到任何的结果。
4、必要的 TAG,就是没办法识别用例是针对基础需求还是扩展需求。这个结果如果成功了是表示属于 QL-1的还是 QL-3的,这些都是未知的。
5、测试步骤的参数不合理。例如有些步骤给出很多的参数,参数的整个的含义是不明确的,这时会对阅读产生困难。
6、不合理的使用。本来应该在初始化环节准备的事情,在测试阶段被用到了,这显然是占用的问题。
7、全局污染、硬编码、重复的用例(常见)会发现
有的用例在前面的测试阶段用到了,在后面的阶段又用到了。在不同的目录里有相似的用例,显然这种用例就是重复的,不应该发生这样的事情。和重复代码是一样的。
8、耗时、过于复杂、不合理的资源依赖,整个检查清单很像一般对代码的检查清单。
有了这个反模式的检查清单做自动化测试的落地具体的建议是什么呢?后面会有具体的例子介绍。先看下面给出的建议。
十、测试自动化落地建议
1、将测试用例与应用代码放在同一个代码库中。尤其保证在改动应该在同一个分支上,这样可以保证开发代码的修改和用例的修改是同步进行的,版本是一致的。
2、在开发前就定义好验收的用例,并在产品代码完成之前实现它们,这样才能知道代码的实现是不是符合用例日期。在开发前就定义好验收的用例指的是在做之前就需要想好验收的标准是什么?怎么测才能在完成前实现这些用例。当产品完成之后可以验证它。
3、测试可以重复执行且与执行顺序无关。
测试是一个原则性的东西不会因为重复执行或者顺序依赖就导致不同的顺序和不同的时间就产生不同的结果。
4、只将稳定有效的测试自动化用例集成到流水线中。并不是越多的测试自动化越好,而是只把有效的稳定的用例拿进来,这样才会有明确和稳定的结果。
5、测试自动化人工验证使用不同的环境。就是不要混用测试自动化和人工验证这两个场景。这两者应该区分开,否则测试之间在环境上会出现偶合。偶合之后会产生冲突。
6、不要用测试自动化验证环境来进行问题定位和排查。
测试自动化用例执行之后,哪怕有错误这个错误应该包含所有足够用户去排查认证,而不需要用户登录到一个环境上做一些定位和排查调试,这个会导致效率的急剧的降低。因为测试自动化环境相对来说是比较有限的,需要更大程度上保障自动化运行的平台和基础设施能够高效的运行。如果在上面做定位排查,就会中断它。如果在上面做也写修改,可能会破环掉整个基础环境,这个带来的成本是非常高的。
7、尽量使用模拟器或者 mock 技术来验证各种异常场景。
这时测试自动化的优势。在遇到异常场景的情况下它比通常的手工测试会更容易验证。
上述提供的测试自动化有经验的同学可能会认为这是面向接口比较多的测试,事实确实如此。其实除了这种测试之外,还有UI测试自动化还有基于流量回放的自动化。针对这种测试其实是有非常多的,在这里就不花费太多之间做介绍了。
除了通过测试自动化的方式能够使验证成本降低,但是本身测试自动化的投入本身也是一种成本的增加。而且做的不恰当的话可能会是一个急剧的增加,可能还不如不做。
另外站在预防的角度来看:
十一、基于(预防)成本考量的单元测试选择性的策略
预防考量单元测试的一个选择性的策略。
1、如何选择性的做单元测试的工作。那么为什么归在预防呢?是因为单元测试实际上是开发的实践,不是测试的实践。所以更多的是开发工程师针对自己代码实现的相应的一系列的工作。
从成本的角度来说,代码可以做简单的象限分类。根据代码之间的依赖,一个函数依赖了其他的函数,依赖了多少?依赖越高成本就越高。
那么做单元测试的时候,函数或者方法要依赖于另一个函数或者方法。彼此之间要测试函数方法的时候,就需要做相应的改装,放在表格里面单独来做测试。意味着要做隔离,就要有成本。所以依赖越多成本越高。
另外从单侧的角度来说针对某一种方法测试的角度来说。收益越复杂的,复杂度越高,做测试收益的就越高。所以从这个角度来说可以做简单的分类。比如一些依赖少,复杂度高的这一类代码叫算法类代码。
里面都是相对偏原生的数据类型,而且相对于其他的来说依赖很少,基本都是别人依赖它。这时针对它来做一些相对应的测试的时候,起码收益是特别高的,一个是本身很复杂,另一个是被别人用到的比较多。所以它的质量好坏是很重要的,而且影响面也是非常广的。另外它依赖别人少,成本很低,所以给它做相应的测试是特别必要的。
针对算法类是必须要做到的。
2、Trivial code 是很简单的代码,一个函数里面只会有一两行调用(系统的调用)。例如打日志就是很常见的 Trivial code。这种代码依赖别人也很少,复杂度也很低。这种就不用做测试了,因为做测试需要很大的成本。
3、coordinators 类型
coordinators 叫做协调型。像 may 函数做相应场景的分装,把相应其他的方法分装在里面。这种方法首先复杂度很低,一般来说就一两个场景。所以没有太多的条件判断。但是它依赖别人特别多,基本都是调用其他类或者其他方法的接口,那么这一种叫做 coordinators 类型。
这种做单元测试的成本就很高,因为逻辑本身很简单,但是依赖项特别多。所以要做很多的隔离,因此针对这个可以不做单元测试,只要做功能型测试的时候测到就可以了。它更适合用功能测试来验证。
4、overcomplicated code 它的复杂度特别大同时又依赖别人特别多。它的数据类型更多的是其他的自定义的一些类或者数据结构。这时将所有的数据都偶合在一起,有复杂的条件判断又依赖特别多,针对它做功能性测试的时候就会发现,逻辑很复杂。做单元测试的时候,又会觉得依赖太多。
针对这种情况建议将算法类或者 coordinators 类型去重构。当然重构需要选择合适的时机,例如本身运行的很好
就留着它就好了,等到有机会再去修改 bug 和缺陷;或者有新功能增加的时候,顺带的改掉一些。专门留一个重构的时间做这件事情是非常危险的。这一个选择性的单元测试的策略同样适合遗留代码系统里再去做相应的功能。
这时就不要一味的要将单元测试达到100%的覆盖率,将所有的单元测试,所有的函数都补上。因为这时单元测试有一个很重要的概念就是需要看单元测试是黑盒测试还是白盒测试。绝大多数的回答都是白盒测试。事实不是。因为白盒测试实际测的是
里面每一行代码的逻辑是什么样的。但实际单元测试是黑盒,测的应该是这个函数里面的完整的功能、完成的需求是什么。只测试输入和输出,里面代码的实现。每个程序员的实现方式是不一样的,如果将其写成白盒,针对某一个程序员可能测到了这种,但是突然有一天这个代码被另外一个程序员修改了,修改完之后单元测试就没用了,但实际需求可能没有发生变化,只是代码的实现发生流量变化,这时就会发现单元测试可能成为了技术负债。
以上已经知道了从哪几个角度来降低成本,质量在选择不同的测试策略的过程中其实在质量和成本中做经济学的平衡。
那么如果说投入了写这样的测试,而且测试是有成本的,那么就要将其写好了,这个成本这么贵,那么什么叫好的测试呢?好的测试是什么样子呢?