醉里乾坤大,壶中日月长

代码健壮性的几点思考

上一篇 / 下一篇  2011-09-09 11:21:46 / 个人分类:细节思考

自动化一直如火如荼的发展的,但同时,很多从业者在经历了最初的热情、激进之后,也会陷入了冷静的思考:那就是投入产出比问题,那就是自动化测试是否真的给测试工作带来了质的改变。

在诸多的引起思考,带来彷徨的理由中,我认为代码健壮性是关键元素之一。这首先要从一个项目说起。

给单位一个项目组做自动化产品,前后五个模块,几百个用例,在我的开发环境中一一调试通过,并且是稳定通过。信心满满的提交给项目组验收,结果出现了很多问题,很多之前可以稳定跑通的case结果变得不稳定。我调试了几个之后,就上去看他们的运行环境,结果发现我的开发环境是WIN XP或者WIN 7 32位的双核处理器,2G内存电脑,而他们的验收环境则是一台XP上的虚拟机,虚拟机内存300M,单核CPU,这给用例运行带来了很多错误。比如,在开发过程中,为了追求运行速度,很多超时等待我都是取小值,而在虚拟机环境下运行,超时时间是明显不够的,所以很多函数返回False。并且由于系统资源太小,在短时间内频繁操作,还会出现产品卡死等偶然情况。反复了调试了很多次,往往顾此失彼,可以说,维护的工作量甚至达到或者超过了开发工作量,而这样质量的代码,手工测试人员也是不相信的,也很难应用到产品测试中去。

也就是因为这个项目,我深刻的思考了代码健壮性的问题。同时认知到一个道理:如果代码不具备健壮性,那这样的代码可以说是无意义的。本身的运行都会由于各种原因失败,更何谈用这样的代码测试产品,没有人会相信结果的。

所以,我修改了我们的测试框架,同时,也强化了一些增强代码健壮性的细节,包括如下这些内容:

1.在框架层面提高运行稳定性:

        之前记得一句话,自动化测试框架使自动化测试成为现实,可见成熟稳定的框架的重要性。在面对批量case运行时,通过框架的调度执行,可以节约大量代码,同时在框架层面添加公共操作,处理case层面的异常,是有效的选择。

        我们的框架采用的是类似白盒测试框架*Unit结构,只不过是自己实现的。在分析了一些产品卡死,运行超时等问题之后,决定将case的执行放到线程中去。

        这里面首先有前提:case是独立单元的,每个case其它case之前不具有强烈耦合性。另外就是,case自身是以函数形式出现,可调用执行的函数。

        之所以选择使用线程而不是进程,只是因为进程在彼此通信之间存在着牵制。耳熟能详的进程通信方式:共享内存、管道、旗语、信号量等等,即便是父子进程之间,在面对大量的数据同步与交互,也会处理复杂。所以选择了线程,统一进程下的线程之间数据同步就方便的多。而且相比于进程,线程更轻量级,所占用的系统资源更少。当然,为了执行逻辑的清晰,也没有采用多线程模式,只是单线程的线性执行用例。

        case函数作为线程的run()函数内容调用,同时设置自定义的线程超时和线程清理函数,这样,在指定时间case执行未完成,则结束case运行并抛一个超时错误,同时执行自定义的线程清理函数,可以将系统环境最大化的清理干净,不影响后续的case执行。

        所以,客观的说,框架层面的控制虽然简单,但意义重大,可保证每次批量用例执行时,整体上的稳定可靠。

        2.在细节层面的技巧提供健壮性:

                  2.1使用消息传递方式取代页面操作:

                           当前很多应用软件使用自定义页面库或者第三方页面库进行UI开发,这些页面元素并非标准控件,甚至有些使用Spy++等工具完全无法抓取到控件,只是图。即便是能够抓取到的页面控件,在操作中,如果使用模拟鼠标键盘操作的方式,也存在非常大的风险。

因为常规的鼠标、键盘模拟,如果在运行过程中,鼠标发生移动,则会造成点击不成功。加入针对每一步的鼠标操作都超时处理,又会带来大量的无效代码和时间损耗。

                           针对这种问题,我们这面采用了消息传递方式来取代了鼠标键盘操作。当然,这需要研发人员的支持,也就印证了之前我们一直讨论的问题:自动化测试的良好开展还是需要研发同事的鼎力支持的。当然,我们这面现在已经是自己在产品代码中添加为自动化测试而使用的消息,这也是一直以来的工作得到了各方面的认可。

                           至于消息中内容的获取,一般采用标准的进程注入方式。这可之前上面提及的传统的进程数据交互不同,略有点Hack性质。

                           在这里不讨论UI测试鼠标模拟更真实等问题。

                  2.2必要时多使用WaitFor函数,同时调大timeout时间:

                           将所有的UI操作使用消息模式取代也是不现实的。有一些情况下也是需要鼠标等操作,或者在一些需要延时等待结果的步骤中,也可能会有timeout操作。在这里要首先选择,是否可以使用阻塞模式,如果步骤为关键步骤,那就直接使用阻塞模式即可,因为即便超时未返回结果,那就说明用例执行失败了,在框架层面会给出超时错误。对于一些比如超时的,可以增大timeout时间,这样可以在某些系统资源有限的情况下,程序依旧可以执行。

                  2.3合理布局函数返回值,保证函数返回值一致:

                           之前很多时候写函数往往很随性,返回值类型可以能代表函数执行成功或者失败的Bool型,也会有代表实际结果的Str或者Int等类型。这样的函数在外部调用时痛苦非常,因为在函数调用后处理时,处理不当就会出现typeError,所以在函数编写前,要思考后本函数的作用,同时确定返回值类型,在函数的所有涉及到返回结果时,给予一致类型的返回值,方便外部调用。

                  2.4必要情况下的Try…Except…处理:

                           Try…Except…出来处理异常是各种语言都有的模式。但到底在何处使用却有讲究。在没有抛异常的语句使用try语句,会降低性能,带来代码冗余,而在需要处理的语句未加异常处理,则会带来运行崩溃的可能。所以,要深刻的了解代码的语句,是否存在抛异常的可能,对可能抛异常的语言要加以处理。

                  2.5清理代码,去掉冗余代码:

                           很多时候,我们的代码都是迭代开发的。往往会罗列一些无用的函数,引入一些无用的类库。这些内容貌似无意义,但却是代码中的隐患。可能在后续的类库更新或者函数变更中爆炸。所以,代码要保持清理,对于无用的引用和定义,要加以清除。

                  。。。。。。

                  还有很多的细节思考,需要在不断的编码历练中加以总结,运用。

 

代码健壮性,说起来简单,但真想写出健壮性的代码也需要大量的实践和总结。不过,这也是自动化发展中的并经之路,只有高素质的自动化编码人员写出大量的稳定可靠的自动化代码,才会让自动化代码在实际测试中被信任,被应用。


TAG:

散步的SUN的个人空间 引用 删除 散步的SUN   /   2011-09-19 12:42:35
看完了...现在我才慢慢意识到你说的这个问题,自动化测试的环境影响因素真的很大,这些都是经验的总结,只能慢慢来了
散步的SUN的个人空间 引用 删除 散步的SUN   /   2011-09-19 11:57:05
现在才看到...先收藏,找个时间好好研究一下经验
xin_晴的个人空间 引用 删除 xin_晴   /   2011-09-19 11:10:23
您好,我是51Testing软件测试网的编辑,您的本篇博文被推荐至51Testing软件测试网首页发表:http://www.51testing.com/html/24/n-245724.html
感谢您关注并支持51Testing博客,期待您更多的优秀原创博文。
tomtang的个人空间 引用 删除 tomtang   /   2011-09-09 16:00:46

收藏
 

评分:0

我来说两句

Open Toolbar