对“画条线”(Draw a line)的单元测试几点想法和实践

发表于:2009-5-06 14:31

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:UniqueStudioWCD    来源:51Testing博客

  可是……不得不面对的是,这种方法确实局限性太大,而且也太明显——这种方法有N大缺点:

  1) 太不保险 我们甚至不能保证我们的代码是不是真的按照Log中写的那样做了,很可能并没有画出线却在Log中一本正经报告给我们已经画了第2条边,宽度是5,坐标值是(16,27,38,49)之类的东西,这种虚假情报很可能会害死人的。

  2) 也太复杂 Assert的时候实在复杂,光是检查三条边是不是一样粗就需要两个Assert,检查三条边是不是连到了一起又需要两个Assert……

  3)代码依赖性 乍一看无非是加上一点点log,可是我们善后的时候可能还要加上条件编译,以防止太多的垃圾信息占用了资源,这些都要修改源代码,相信没有多少人愿意去做这件事情;另外当源代码的数量增多的时候,复杂度也就相应地增加了。

  刚才已经绞尽了的脑汁再拿来绞一次,想2条这种方法的好处:

  1) 告诉我们我们的代码是怎样做的,而不是做了什么(也就是How而不是What)

  2) 给我们一点点自欺欺人的自我安慰(我们这些代码是做了测试的。。。你看测试覆盖率摆在那里的)

  ● 改进版Log法

  这种方法之所以称之为改进版主要是因为我们采用了让代码自己记录行为的方法——我们需要写一个新的Graphics的子类,就叫做CustomGraphics吧,然后重写其中的一些方法,比如在DrawLine方法,我们需要可能需要这样干:

     public override void DrawLIne(int x1, int y1, int x2, int y2)

     {

           base.DrawLine(int x1, int y1, int x2, int y2);

           ActionLog("DrawLIne(int " + x1

                                       +", int " + y1

                                       +", int " + x2

                                       +", int " + y2

                                        +")");

     }

  或许这个样子会更好:

     public string ActionSaveAsText = "Do nothing";

     public override void DrawLIne(int x1, int y1, int x2, int y2)

     {

           base.DrawLine(int x1, int y1, int x2, int y2);

           ActionSaveAsText ="DrawLIne(int " + x1

                                       +", int " + y1

                                       +", int " + x2

                                       +", int " + y2

                                        +")";

     }

  之后其他的事情跟Log法中一样,这样做显然会极大程度上减少我们在源代码中的ActionLog的数量,但是我们同样需要修改代码:我们要使用 CustomGraphics而不是以前的Graphics类,我们还要保证我们使用过的方法中都增加了相应的 ActionSaveAsText = "...";方法,这样看来,我们同样轻松不了多少。

  Notes:额,可能前面我给大家传递了错误的信息吧,其实我的测试对象是自己写的一个函数 DrawALine,那个函数可以接收各种参数,然后画出一条线,而不是说我去测试.net中已有的DrawLine方法,这个方法当然是不需要我们去测试的。或许我应该改成DrawTwoLines来测试,这样就不会引起误会了~~

  ● 截图法

  好吧,上面的话已经讲完了,想扔砖头的使劲扔过来吧,我正好没钱买房子,说不定可以凑点砖头自己垒起来一层~~接下来介绍的,看起来是另外一个麻烦的东西。从名字上看,你可能会想说:是不是就是画完图之后把图片接下来然后比较图片啊。如果你这么想的话,那么恭喜你,我确实是这样想的——刚才脑汁已经绞尽了两次了,所以也想不出什么更好的办法了,只能拿这个方法来凑一凑数。

  大体思路是这样的:

  步骤1:运行待测方法DrawALine,在Winform窗口上画条线

  步骤2:检查画的线是否正确

  步骤3:保存刚才画的线为图片形式

  步骤4:在测试代码中重复上述操作,并将测试代码中得到的图片跟手工运行(调试运行)得到的图片进行比较

  上述步骤其实跟我们常见的单元测试过程很接近(当然这里不包括TDD中的测试,而是传统的流程中先代码后测试的顺序)。难道我们找到银弹了,难道事情就这样被解决了?显然不会这么简单……不过为了安慰一下我和大家受伤的心灵,我们先来展望这种方法好处:

  1) 准确性提高 如果是两个一模一样的图片,自然我们画的图就是对的了,而且我们还可以拿截下来的图好好瞅瞅,随机抽查一下我们的DrawALine上不上镜,是不是照的艺术照给照得面目全非了——毕竟我们需要的是Draw出来的是A 真是的Line。

  2) 源代码的修改少 这是另外一个很大的优势。试想我们只是运行一下DrawALine方法,DrawALine方法帮我们把线画出来,然后我们拍个照带走跟之前的标准像比较就成,不需要在源代码中作额外的事情。

  看到上面的展望,心情有点激动,似乎真的是银弹,不费吹灰之力就摆平了,很好很强大。。。Ok,在YY过后我们应该清醒过来了,我们还要事先预估一下可能遇到的问题以及这种方法的缺陷:

  1)截出想要的图 我们能不能在运行了DrawALine方法之后顺利的截出我们想要的图,而且要跟标准像大小位置一致,这个需要再想一想。

  2) 图片比较 要比较两张图是不是完全一样

  3) 图片保存 标准像怎么保存,不同的方法不同的用例的标准像要怎么保存?而测试运行过程中的图片是否要保存下来以供抽查,这个又怎么保存?

  4) 运行速度 对于单元测试来讲,我们希望很快运行完毕,而我们的这种办法是不是存在效率地下的毛病?

  ● Mock法

  对于很多人来讲,Mock也许是解决此类问题的不二法宝了吧:)就连很多介绍mock的文章中提到mcok的最佳应用环境时候,都不忘提到UI相关的单元测试是它的强项。关于Mock法,自然也有一些它的劣势,比如过于死板的一条道儿走到黑——对原代码的实现方式依赖性较大,而且Moss也不能满足某些人的需要,让他们亲眼看到这个程序真实的运行效果。

  总的来讲,正如楼下兄弟说的那样,Mock应该是最佳解决方案了,至于上面的截图法可能略显得臃肿,也显得更像是功能测试而非轻便的单元测试了。

  总结

  断断续续整了好几天,终于整了一点点眉目,对于第三种截图法,笔者也已经有了一些初步的代码,相信在下一篇文章中可以拿出来跟大家一起分享。不过稍显遗憾的是,笔者没能找出其他的更方便的方法,比如是不是存在这样一种方法,把DrawALine的结果也可以描述成对象,然后直接比较对象的属性;亦或者其他的笔者想都没有想到的地方和方法?对于上述介绍的方法,欢迎大家扔砖~~

  后记

  由于本本上面的开发环境崩溃的原因,本文中的代码并未在IDE中调试,代码中可能有一些因疏忽导致的纰漏甚至弱弱的语法错误,而代码的颜色也不如VS中那么容易辨认,给大家阅读造成的困难敬请原谅~~

22/2<12
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号