`
binbinhu1987
  • 浏览: 20053 次
  • 性别: Icon_minigender_2
  • 来自: 杭州
社区版块
存档分类
最新评论

以自动化测试撬动遗留系统

 
阅读更多

面对遗留系统,选择合适的测试策略,能让自动化测试的投入在一定时期内看到效果,并且建立可持续进行的机制。同为自动化测试,每种测试在面对遗留系统时遇到的挑战是不同的,起到的效果也不尽相同。

  背景

  我目前所服务的企业大部分系统是遗留系统,其中多数处于相对需求平稳阶段,即需求并不多,也没有大需求。但这些系统牵制了和需求所需人力不成比例的大量人力,从系统本身的原因看,有这么几点。

  ● 系统晦涩难懂,可读性可理解性很差。理解原有系统往往占据了进行一个修改的大部分时间。

  ● 系统设计僵化,改动困难,一个小修改,会迫使系统很多部分的改动。

  ● 系统难以重用,大多软件单元缺乏可重用性。

  ● 系统脆弱,引入一个小功能会引入几个缺陷,修复一个缺陷又引起几个新缺陷。

  投入大量人力,产生的价值却微乎其微。面对激烈的市场,同质化的竞争,成本和质量问题日益凸显。而所谓遗留系统,即没有自动化测试保护的系统。客户很希望通过引入“自动化测试”来提升系统质量,最终帮助他们建立自动化测试机制。

  过去几个月里,我先后投入到几个遗留系统的自动化测试提升工作中。这些工作都进展不错,很多系统的核心模块都有了自动化测试的覆盖。另外,这次专门针对“遗留系统”所做的自动化测试工作,也带给我一些新想法:自动化测试,很可能是我们撬动遗留系统的一个支点。

  测试策略选择

  图1是测试金字塔模型,从上至下分别是验收测试、API测试、集成测试和单元测试。你可以有不一样的分类,但从上至下,测试粒度越来越小,测试数量越来越多。一个具备完善自动化测试的系统,应该具备类似的测试分布。

图1 测试金字塔模型

  当我们面对的是遗留系统时,追求理想模型肯定是不现实的,那么应该选择何种测试策略呢?

  每 个遗留系统的状况都不尽相同,可能选择的策略也会不一样。但有一点是一致的——所有的测试都不是没有成本的,在人力并不宽裕的情况下,必须让测试投入“值 回票价”。而且,必须让测试投入到短期最有价值的地方,才能让团队尽快看到效果和建立信心。我们选择的策略之一是:快速建立稳定性较高的功能测试防护墙, 以此保护系统的核心功能不被任意破坏。这里有两个关键点。

  ● 快速,要选择可以快速建立的测试,让一定的价值在短期之内就能得到体现。

  ● 稳定,指的是测试本身的稳定——不因系统变化而对测试产生太大的冲击,因而维护成本也就相对较低。

  这里的功能测试可以是验收测试、API测试或集成测试,根据每个系统的情况选择更好满足上面两个关键点的测试类型。

  例如,我们曾面对一个Web系统,大部分页面逻辑比较简单,主要是呈现内容;前端通过REST接口跟业务后台交互数据。刚开始我们选择基于 WebDriver的验收测试,但随后即发现这类测试编写成本较高,需要学员掌握较多技能,无法在短期内快速为整个系统建立一个防护墙;另一方面,它的稳 定性也较低,测试较易受到页面布局的影响,维护成本较高。在这种情况下,最后我们转而选择了基于REST接口的测试,因为它的建立成本更低,稳定性也更高 (REST接口变化较少),而且也可以覆盖所有核心功能,相比而言,是个更好的选择。

 

我们还选择了另一个策略:针对热点区域(包括需求热点和缺陷热点等)添加测试。选择这些区域主要基于两点理由。

  ● 首先,“非热点”区域,也就是暂时稳定的区域,在初期并不是最值得投入为其建立测试的。例如,有个Web系统,它有两个相对独立的组件,一个是社区,另一个是网店,如果前者是热点区域而后者不是,那么前者就更有价值在初期投入建立测试。

  ● 其次,遗留系统的脆弱性往往体现在“Bug重复出现”、“解决一个Bug,出现两个Bug”等情形。针对这些活跃区域添加测试可以对它们起到保护作用,减少出现上述情况出现的机会;同时,也是对这块区域的一个重构契机。

  针对“热点”区域,我们一般会在团队中建立类似“完成新需求必须同时完成测试”、“修复缺陷必须添加测试”这样的纪律。

  同时,选择合适粒度的测试也很重要。各类测试自己的优点,例如集成测试在功能保护上体现效果更快;而单元测试却会驱动内部质量的提升。如果条件允许,选择多 种粒度的测试结合,别忘了之前提到的测试金字塔。我们无法为整个系统一下子建立完善的测试,但为某一个区域,是有可能的。

  为遗留系统写功能测试

  功能测试处于测试金字塔的上端,它的稳定性相对较低,维护成本也较高。因此写功能测试一定要关注提升它的稳定性,并降低维护成本,遗留系统在这几个方面遇到的挑战可能会更大。

  最近我对一个Web系统建立基于WebDriver的功能进行测试,其中面临的一个很大问题就是HTML页面缺乏语义、很多元素的定位都得依靠位置等极不可 靠方式,一旦页某些布局发生变化,就会影响到测试,维护成本很高。但事情总有两面性,正是这些测试,让页面的重构和优化得到了团队的重视。

  影响功能测试稳定性的另一个重要因素是测试数据。对于团队控制范围内的系统,我的建议是随着测试的建立逐步创建一套可靠的、覆盖各种典型场景的测试数据准备脚本。由此,我们每次都重新建立干净的测试数据,让测试更加稳定和可控。

  但在遗留系统中,有时会碰上更严峻的问题,系统依赖于第三方或其他不在控制范围内的测试系统。功能测试会影响到测试数据,因此我们的测试很有可能无法重复执 行。当然,建立一个测试替身系统是一种选择方案,但有时并不容易,至少短期之内。面对这种情况,我们的解决方案是让测试程序和测试数据解耦。想象一下,如 果同样的测试由一个测试人员手工执行,每次执行时不需要选择相同的数据,而只需选择“符合同样要求”的数据。

  例如一个电商系统,它出售数量 有限的商品,售完即止。测试数据库中有大量不同商品,但每种商品数量所剩无几。如果我们的商品购买测试程序针对某个特定商品,那么在运行几次之后,商品就 会卖完,测试就不再具备可执行性。但测试人员不会这么傻,他每次都可以选择还有剩余的商品进行购买测试。既然如此,我们的测试程序也同样可以做到:只要根 据商品页面上的信息识别出哪些商品有剩余,随机或者有策略地选择其中某个商品进行购买即可。

  这样,我们就让测试程序和具体的测试数据得到了解耦,缓解了测试的不可重复执行性,使其更加稳定,维护成本也得到降低。除了上述方法,还有其他方式可以避免测试程序和测试数据的耦合。

  功能测试程序,是在用一种自动化的方式代替人的手工执行,但同时也一定程度上丢失了手工执行的灵活性。让功能测试程序保持灵活应变是我们在编写测试程序时应该考虑的一个重点。

  为遗留系统写单元测试

  为遗留系统写单元测试会面临和写功能测试不一样的挑战,在复杂度及对人的能力要求上也可能会更高一些。原因并不在于测试,而在于遗留系统自身。遗留系统内部 的强耦合(依赖)及每个单元的高复杂度使得测试难以开展。例如最近我接触的几个遗留系统,线程池逻辑和业务逻辑交织在一起,SQL拼装逻辑、ORM逻辑和 业务逻辑也交织在一起,一个方法往往几百上千行,而且有很深的调用链。

  为这样的系统编写单元测试,我们普遍遇到了这样几个问题。

  1、私有方法如何测试:我经常被问到的一个问题是“这个私有方法怎么测”?对于私有方法的测试,可能的答案是——不要对私有方法进行测试,只要测试公有方法, 就能覆盖到私有方法。这个答案可能正确,但在遗留系统中,往往是错误的。很多时候,我会反问“为什么要对私有方法进行测试?”

 

下面这个例子(如图2所示),是一个有较复杂逻辑的线程。但主要的逻辑存在于组装和发起HTTP请求和解析返回的XML上。

图2 一个有较复杂逻辑的线程

  当想对私有方法进行测试时,往往意味着类过于复杂、私有方法承载着太多的职责,通过公有方法覆盖私有方法的测试成本过高,难度太大。因此,更好的解决办法是 分离职责、分而治之、单独测试。通过分离职责,单独对各部分逻辑进行测试,测试就会简单很多,如图3所示;另一个例子如图4所示。

图3 单独对各部分逻辑进行测试

图4 另一个案例

  如果在不改变代码的前提下为这样的代码写测试,首先要花很多时间理解它,理清各个分支,分别为它们建立复杂的测试准备状态等,成本很高,有时甚至为不可能完成的任务。

 

2、Mock是否是遗留系统单元测试的“银弹”:当对遗留系统进行单元测试时,Mock作为“银弹”时不时地出现了。面对遗留系统中有较深依赖链的一些方法, 把那些难以建立的依赖统统Mock掉是最快的手段。但经验告诉我:对Mock保持警惕,一旦引入它,就容易被人滥用。当然它本身无错,错在使用它的人,如 果一定要怪Mock,就怪有些Mock工具过于强大吧。滥用Mock会导致:

  ● 测试真实性的减弱,降低测试程序作为测试本身的价值;

  ● 滥用Mock的“交互验证(Verification)”,使得测试和实现紧密耦合,降低测试的稳定性。

  我专门回顾了之前做的几个系统,发现用到Mock的时候微乎其微,大多使用在对不受控依赖建立测试替身上。在保证测试执行速度的前提下,这是我推荐的做法。但面对遗留系统时,我们很容易把“难以建立依赖测试状态”作为使用Mock的借口,大量滥用。

  单元测试,相对于功能测试等高层次的测试,是代码级别的白盒测试。但之于它的测试对象而言,我们仍然应当把单元测试视为黑盒测试——单元级别的黑盒测试。例 如对一个排序方法而言,不管它采用什么排序算法实现,大多情况下我们只在乎它是否可以将一个无序数组排序。它的测试也只要基于输入(无序数组)和输出判断 (有序数组)即可,就算排序算法改变,测试仍然不受影响。从这个排序方法的角度看,测试对它的内部实现不关心,是黑盒的;当内部实现改变时,只要外部行为 不变,测试就不会受到影响。滥用Mock很容易让测试违反这个特质。

  此种情况下,我们选择的方案是:选择从依赖链的末端开始测试,从这里开始逐渐完备测试状态准备机制。在保证测试速度(运行速度和编写速度)的前提下,尽量避免使用Mock。当然,如果你的代码依赖复杂、混乱,那么首先可能要重构,重新组织分配职责,简化依赖关系。

  简而言之,面对遗留系统进行单元测试时,有几个值得关注的实践:

  ● 分离职责,分而测之,优于私有方法进行测试;

  ● 逐步完备测试状态准备机制,优于使用Mock。

  之前,我个人对于在遗留系统上实施测试自动化建设是总体悲观的:遗留系统庞大,测试的效果并不会在短期内得以体现;而团队,恰恰经常认为遗留系统足够稳定 (没有什么大需求,而且90%的代码可能短期不需要改动),没有动刀的必要。因此,大多数团队很有可能会在看到测试带来的效果之前就放弃了。

  但请相信我,这一切都是假象。故障频发的正是这些遗留系统:

  ● 稳定是假象,遗留系统里隐藏着很多故障和漏洞,只是暂时没有爆发而已;

  ● 稳定是假象,粗劣的设计让任何一个需求的变化都会像霰弹一样影响整个系统,遗留系统大都是极其脆弱的。

  而单元测试,除了它本身带来的测试价值之外,对于遗留系统而言,更大的部分在于以下三个方面:

  ● 驱动遗留系统的重构,提升架构设计和内部质量(遗留系统虽庞大,但坏味道其实都雷同)。这是对遗留系统而言最关键但一般情况下最没有可能去做的事情;

  ● 暴露并解决系统中的缺陷和漏洞,在这个过程中,我们发现并处理了很多漏洞和缺陷,包括多线程处理上、业务逻辑等;

  ● 更重要的是提升团队的重构和设计能力以及团队质量意识,特别是内部质量。

  总结

  面对遗留系统,选择合适的测试策略,能够让自动化测试的投入在一定时期内看到效果,并且建立可持续进行的机制。同为自动化测试,每种测试在面对遗留系统时遇 到的挑战是不同样的,它们起到的效果也不尽相同。对于遗留系统而言,功能测试是盾,只有它的保护,我们才能放心地对遗留系统动刀;而单元测试是刃,它撬动 的不仅是遗留系统,更是遗留团队。

 

摘自 http://www.51testing.com/html/04/n-834404.html

分享到:
评论

相关推荐

    以自动化测试撬动维护阶段的遗留系统

    以自动化测试撬动维护阶段的遗留系统!面对遗留系统,选择合适的测试策略,能让自动化测试的投入在一定时期内看到效果,并且建立可持续进行的机制。同为自动化测试,每种测试在面对遗留系统时遇到的挑战是不同的,起...

    遗留系统重构与维护

    2. 自动化测试:构建全面的自动化测试套件,确保重构不会破坏原有功能。 3. 代码审查:通过代码审查保证代码质量,提供即时反馈。 4. 跟踪进度:使用项目管理工具跟踪重构进度,确保按计划进行。 5. 沟通协作:与...

    改善Java遗留系统的8个技巧

    无论是通过使用分析器深入检查应用,还是通过自动化构建和部署简化开发流程,或是通过创建单元测试提高代码质量,每一步都对提升遗留系统的稳定性和可维护性至关重要。同时,监控数据库使用状况、利用JMX增强运维...

    一种Java遗留系统服务化切分和封装方法.pdf

    在Java遗留系统服务化切分和封装方法中,作者提出了一种自动化的服务化切分和封装技术,以解决遗留系统服务化的难题。该方法通过综合静态类结构模型和动态对象调用模型,建立了一种遗留系统的对象依赖频度图表征模型...

    可视化的遗留系统微服务改造(54页).pdf

    随着业务需求的不断变化和技术的快速发展,如何有效地对这些遗留系统进行现代化改造,以适应新的业务场景和提高系统的可维护性,成为了业界普遍面临的难题。微服务架构作为一种新兴的软件架构模式,以其松耦合、可...

    办公自动化系统测试报告 (2).pdf

    【办公自动化系统测试报告】 测试报告是对软件质量保证的关键步骤,尤其在办公自动化系统(OA系统)这样的企业级应用中,确保系统功能、性能和可靠性的完备性至关重要。本报告详细阐述了对OA系统的测试过程、原则、...

    遗留系统SOA迁移解决方案

    综上所述,对于那些希望克服遗留系统带来的挑战、加速数字化转型的企业来说,SOA提供了一个有力的工具箱。通过精心规划和实施SOA解决方案,不仅可以解决当前的问题,还能为未来的持续发展打下坚实的基础。

    办公自动化系统测试报告 (3).pdf

    【办公自动化系统测试报告】 测试报告是对OA系统进行全面评估的重要文档,目的是确保系统在投入运行前达到设计目标,具备良好的功能、性能和可靠性。软件测试是软件质量保证的关键环节,它旨在通过执行程序来发现...

    办公自动化系统测试报告 (2).docx

    【办公自动化系统测试报告】 测试报告的目的是在软件投入运行前,通过软件需求分析、设计规格说明和编码的复审来发现并纠正错误,确保软件质量。OA系统功能测试是检验系统是否达到设计目标,包括功能、性能和可靠性...

    一种Java遗留系统服务化切分和封装方法

    一种Java遗留系统服务化切分和封装方法

    系统集成测试报告.docx

    - 加强自动化测试,减少手动测试的工作量,提高测试效率。 - 提升测试覆盖率,特别是对于边界条件和异常处理的测试。 - 实施持续集成和持续部署(CI/CD),快速发现并修复问题。 - 定期进行性能压力测试,识别并优化...

    在大型遗留系统基础上运作重构项目

    - **测试缺失**:系统缺乏充分的自动化测试覆盖,增加了代码变更的风险。 - **代码质量低下**:存在大量的“copy & paste”现象,代码重复率高,维护成本增加。 - **功能扩展困难**:由于以上问题的存在,新功能的...

    论文研究-历史遗留测试系统的分布式开发策略.pdf

    提出了利用中间件技术对历史遗留测试系统进行分布式开发的策略:对计算机配置高的历史遗留测试系统,结合其特点探索出了一种高效率、高性能的基于CORBADCOM的分布式开发方案;针对数控测试系统,则巧妙利用数据库...

    JXC系统测试报告JXC系统测试报告

    - **容错性评估**:测试系统在遇到异常情况时的处理能力,如错误的数据输入、网络中断等。 - **需求符合性**:确认系统功能是否符合用户的显性和隐性需求。 - **自动化测试**:利用QTP工具自动化测试过程,提高测试...

    企业微信配置发消息- 自动化测试报告篇.docx

    【企业微信配置发消息自动化测试报告】主要涵盖了如何利用企业微信接口发送自动化测试报告,并结合Python脚本实现这一过程。以下是详细的步骤和知识点解析: 1. **发送消息接口说明** 企业微信提供了官方API(应用...

Global site tag (gtag.js) - Google Analytics