随着测试成为一门“专业”,所涉及到的范畴比较多,中培伟业《软件自动化测试与持续集成实践》培训专家张老师在这里就软件测试的一些重点问题进行了介绍。
1. 单元测试
单元测试在软件工程中隶属开发过程域,开发团队在完成一部分代码(一个类、一个方法、函数)时设计对应的单元测试用例来进行验证这部分代码是否按预期进行执行的行为。
实际上单元测试提了若干年,但这若干年里鲜有公司能将单元测试的覆盖率提升到50%以上,60%的公司从不做单元测试。
为什么出现这个结果呢?
一方面,开发人员认为完成功能是首要任务,总觉得来不及也没有职责做单元测试。修复后期别人发现的一大堆bug认为是想当然自己的工作,为了预防和减少这些bug认真的做一把单元“测试”却不是自己职责所在了?很有意思的习惯性思维。想起多年前刚参加工作时,公司贴在座位旁边的的一句话“你的下游就是上帝”。我们在交付下游(测试团队/客户)我们的东西时,我们应该做到什么程度?
另一方面,开发团队对单元测试的重要性认知不够。为什么认知不够呢,因为缺乏对bug/故障的总结与分析。这属于典型的做项目的一次性交付思维,项目/新需求交付即表示完成。事实上这个总结分析非常重要。大家可以尝试着从重大故障库里翻阅一下历史上的重大故障,有些很低级的,比如结构体初始化错误、数组越界、变量类型错误、逻辑缺失、甚至select忘记了where条件都有。其实这些错误,在自己编码阶段完成可以通过单元测试/同行评审/代码扫描检查等方式发现,何必出现重大故障时扼腕叹息?Boris Beizer:软件历史上最臭名昭著的错误都是单元测试可以发现的错误。
再谈谈单元测试的执行方法。结合性价比及开发团队现状,建议单元测试:
1) 先从核心代码/核心模块入手做;核心代码/模块的单元测试行覆盖率要达到60%,方法/函数覆盖率达到90%;
2) 单元测试用例先从基本逻辑路径覆盖、出错处理、接口、边界条件四个方面设计;
3) 结合单元测试工具框架Xunit及Xmock(打桩用)来执行;
4) 结合同行评审/自动自动静态代码扫描(findbugs/PMD/Cppcheck等)来执行;
5) 结合持续集成来执行,随时看到全景视图;
2. 功能测试
功能测试(含软件工程中的集成和系统测试)经过多年的项目实践,相对来说控制过程已经相对较为成熟。重点把握住几点:
1) 波次需求-波次开发-波次测试-波次发布;
2) 开发、测试、编译、生产环境相对独立且权限受控;
3) 测试人员对业务的深入理解+测试用例的整理及测试要点;
4) Bug系统及bug跟踪、Bug度量;
5) 适当频率的回归测试应对增量开发;
6) 实际使用人员的参与测试很重要,比如工单补录、模拟测试;
7) 先从端到端核心流程的穿越测试入手再扩大范围测试;
8) 重大专项的测试把握颗粒度,从最易出错处考虑;
9) 最好版本管理+持续集成工具框架。
3. 自动化测试
很多年来一直有一个误区,认为自动化测试能替代手工测试。事实上,目前没有一家公司完全通过自动化测试来替代手工测试的。拿一个需求简单对比执行时间:手工测试的时间=用例编写(文档)+用例执行;自动化测试的时间=用例编写(文档)+自动化用例设计调试+自动化用例执行。所以从普遍功能测试上看,自动化测试不会比你单纯的手工测试执行更快。
但我们还是要去持续推动自动化测试呢?因为我们面对的是迭代增量迭代开发模式(敏捷也是高度迭代),我们已经测试的功能在新的功能增量上来后还好用不好用,受不受影响?从工程实践的统计来看,经过多次版本增量迭代后,在上线前约30%的已经测试过的功能受增量代码交叉影响而又出现bug。所以我们要对已经测试的功能做出自动化用例,当新增/迭代的版本/功能上来后,我们可以手工测试新增的版本/功能,同时启动已经测试过的功能的自动化用例执行。这样就能发现已测试过的功能是否受到后来功能版本的影响而导致的bug,又省略全部功能测试一遍的烦恼。因为一个项目过程中有多次迭代和增量,那么这个规模效应就越发显现。在新需求开发过程中更为重要:将核心功能做成自动化脚本,每次上线的时候自动化执行那些核心功能的自动化脚本+手工执行本次上线需求的测试。
自动化测试脚本还应用在一次传入多个测试数据的场合。
自动化测试的应用场景分析清楚后,我们再谈谈为何自动化测试即便用在回归测试这种场合及它的作用和效果,业界公司为何仍然很少能规模、例行的做起来呢?
1)受限于自动化测试框架。目前业界的主流自动化测试框架,例如QTP、selenium、watin、watir等全部都是基于界面的自动化工具,基本原理都是捕获界面组件(按钮/下拉菜单/弹出框等)的动作,重新执行一遍这个动作来完成验证。这里面涉及到界面组件的任何变化,比如位置、比如内容、比如触发方式、比如执行环境等都需要修改和调试自动化脚本,带来较大的维护工作量。常常地,执行一遍自动化测试脚本报出若干个各种类型的错误,真正定位是bug的又少,越来越失去信心,最终放弃。
2)前期的测试人员投入和坚持。我们上面分析了自动化测试的特点,所以要自动化测试例行落地,必需前期有一定的人员投入(最好测试人员分一部分精力来做),随着脚本维护的数量和脚本的数量积累,才能有一定的规模效应出现,最终体验到自动化测试的乐趣和价值。自动化测试还要有所坚持,因为根据上面分析的自动化测试特点,有时候很多次自动化用例执行不一定能发现关联错误,关联影响的错误毕竟要大幅度少于新增功能测试的错误。不能因为发现的bug少就认为价值小最后失望告终。
在自动化测试的落地实施上,我们建议:
1)范围:新需求开发过程/长周期界面不易变化的项目建议做自动化测试实施;短周期项目不做自动化测试,界面易变化的项目不做自动化测试;
2)工具。互联网类可尝试python+webdriver+robotfromwork的自动化测试框架,这个框架之所以成为互联网近期关注的热门。主要还是python脚本语言的简单好写跨平台的特点,再结合robotfromwork的用例管理及表格化编写用例带来方便性。但是正如我前面的分析,目前这类工具都是界面型工具,有天然界面变化引起维护的这个弊端。所以我们还是要强烈推荐我们自有研发的自动化测试工具Sitechtester,这个工具主要是抛开界面,将界面访问逻辑的过程封装,只需调服务和传测试数据,因为在脚本制作上和脚本执行上都比较快。目前自有工具的主要弱点是C主体开发,在跨平台使用和编写用例上要求更具程序基础,对于测试人员的使用有一定技术局限。
3)资源。虽然我们寄希望长期降低成本。但是不得不面对,我们在自动化初期的人员投入脚本编写和脚本维护及自动化环境搭建等过程,建议可先从核心功能做出自动化用例,先现有人员分离部分职能来做自动化测试。
4. 测试用例
测试用例的重要性、设计方法在这儿不再阐述,我主要想表达下测试用例的积累和复用。我们知道,如果一个项目/产品的代码重新开发的比例超过30%,这个产品/项目基本上来说是比较失败的。测试用例亦如此。同样产品/项目的测试用例应尽量复用或者在复用基础上进一步修改使用,总比全部重新来写的好。
所以要强化测试用例收集和复用的工作。收集后就是复用的问题了,先有地可寻,再强化复用。
测试用例的复用要遵循:对于项目还是建立按照产品树-构件-测试用例,转到项目树的产品构件下的测试用例对应即为复用/修改属性带过去。对于新需求,每个产品要建立最小回归用例集,需求上线时确保该部分用例覆盖测试到,包括测试场景及测试数据等。
5. 敏捷开发与敏捷测试
敏捷开发和敏捷测试我们这儿不去谈论它的好坏。依据我们的了解,国内真正做起敏捷开发/敏捷测试的公司也屈指可数,而且多数变了形。
敏捷真的好的事物,关键是我们怎么用它。
在测试方面,关键的是我们对敏捷测试的态度是不要照猫画虎,应该更多的学习和借鉴它的一些方法和思想:
1)划分波次的思想,先划分系统的主干功能,一个波次一个波次的整理需求、设计开发、集中测试、波次交付。这样最大限度的避免了原来我们领到任务后,黑箱操作几个月到半年再一次性集成发布,结果要花费巨大的时间来解决集成和缺陷。波次思想的核心就是通过一次次端到端的潜在集成替代了原有的黑箱操作完毕一次性集成发布。
2)测试人员和开发人员的沟通应该是以bug为中心随时、无障碍、互相坦诚相见,而不是传统意义上的“相互对立”,因为目标是统一的。敏捷中的站会、总结评审会就解决了这些矛盾。
3)测试计划应该详细做最近一个波次的,更远波次的测试计划只做总体计划。这个有好处的,其实我们都深刻有体会,计划跟不上变化。能把握的是最近的事和人。
4)敏捷中测试用例突破原有的标准文档模式,可以通过示意图、测试要点(站会时随时记录)等方式来呈现,核心是你是否真的理解和掌握了你所测的东西。但不管何时方式呈现,都要积累下来,以备复用。
5)敏捷始终强调质量内建,也就是说测试不是保障质量的唯一环节,质量更应该是越早解决越好,体现在规划阶段的FDD、开发设计阶段的极限编程(静态代码检查、同行评审、单元测试、结对编程、持续集成等)、项目管理过程的scrum(共同分享信息,关注总结)等;
6)工具。不管我们是否采用敏捷,伴随着敏捷,一大批开源工具可以被我们使用和掌握。比如持续集成的相关工具(jenkins/maven/ant等)、测试驱动开发的工具(fitnesse等)、代码检查的工具(findbugs等)、自动化测试工具selenium工具等。
5性能与安全测试
性能测试本身不再多说。我这儿想要说的产品/项目的性能不要单单放在性能测试的时候才去关注,到那时候产品的性能bug修复代价太大了,开发测试团队日常中就要关注产品性能。
对于设计团队来讲,比如批量与数据库交互设计、充分利用缓存和存储层推前、多进程与集群设计、分表与分库等都会对系统性能造成重大影响;对于开发团队来讲,你代码中申请的内存不要忘记回收(malloc/free,new/delete)以免造成内存泄漏、你get的线程使用完毕要close掉、你的报文传输压缩、CSS置前JS放后、请求合并处理、减少硬解析、正确使用索引等等都是避免后期性能的简单而有效的方法,你编码的时候考虑到了就好了。
安全测试随着近年来重大安全事件的暴露而变得热门。安全测试本身的技术和方法并不复杂,你用appscan、zap等工具,一会儿跑出大片安全漏洞就ok了。当然测试团队也要理解安全漏洞的原理和攻击方法。
本质还是开发团队要有针对性的避免和减少安全问题。因为一旦工具跑出一堆安全问题,要不要修改?修改的代价有多大?我认为还是比较大的一个量的估算,比如数据字段加密,你是加了密了,加密后传给对方是否要解密还是对方解密等等涉及的面很多。必需要有取舍。否则根本按期完不成功能交付。建议:
1) 对于面向互联网普通大众的系统,从根本上要控制认证和授权、数据加密保护和传输这两个主要切入点。关键动作必须重新认证(不要信任session)。关键数据必须加密保存和传输,注意提醒那些还沉浸在MD5加密的人们,这个早就被破解了,更不要用自己的加密函数。面向互联网普通大众的系统还要重点考虑网络攻击(比如Ddos攻击,这时候防火墙是解决不了的)。
2) 对于传统渠道产品,比如支撑系统、经分系统等,因运营商有4A等类似单点登录的统一认证系统,认证和授权可以适当充分信任4A等系统。更多的是从合法用户的非法行为入手考虑,比如合法IP的刷机行为、合法用户的盗权行为、合法用户的信息泄漏行为(强化数据加密)。
先写这些,感觉要写的很多。后面再推出个(2)吧,重点谈谈持续集成、国内外优秀工具测试的实践及分析我们的差距。……