防御性编码和单元测试规则(二)

原创 2004年08月10日 23:51:00

加强警戒(En garde)!

要记住,您的客户对您的产品有与您不一样的想法。他们会在一个您的小组很可能从来也没想到的 —— 或者至少是没有可能测试的 —— 环境中安装它。他们会以您从来没有想到过的方法使用它,并以您意想不到的方法配置它。下面的列表有助于帮助您保证他们不会发怒:

验证所有收到的参数的完整性(考虑如果您期待一个数组而传递来的是一个 null,但是您在索引数组之前没有检查这种可能性时会发生什么情况)。

考虑所有可能的错误情况并增加处理每种情况的代码(您希望代码得体地处理错误条件而不是堵塞它)。

对于那些未预料到的错误条件,加入一个一般性的“捕获所有”错误处理程序。

在适当的时候和地点使用常量。

在代码各处加入跟踪和日志。

如果您的产品将翻译为另一种语言,那么保证您的代码可以“支持”它。即使出现这种情况的机会很小,但是提前计划总是好一些。修改代码以使它提供支持是最容易产生缺陷的。下面是几个您要考虑的与支持相关的问题:



  • 您是否有任何硬编码的字符串?

  • 您是否正确地处理不同的日期/时间?

  • 不同的货币表示呢?



还有,在代码中使用大量断言。

给您的代码加上充分的 注释。总之,您还记得在六个月前编写那个方法时的想法吗?一年后要修改您的代码的某个人又会怎么想呢?在我们提出的所有建议中,这一条可能是最重要的。

单元测试(防御性测试技术)

在本文中,我们所说的 单元测试 是开发人员在自己的代码正确编译后、在交给功能测试小组之前进行的所有测试和分析。正如我们在 这只是一个测试 中提到的,主动进行单元测试并 在测试时像一位测试者那样思考(即,必须往坏处想、热衷于破坏并喜欢恶作剧)是很重要的。下面是在单元测试时要记住的几件事。

静态代码分析工具

第一种,也是最容易的分析代码的方法是让别人替您做 —— 或者像在这里一样,让其他 工具 替您做。有一些不同的静态代码分析工具可用,从综合性的工具 —— 一些开发机构实际上在他们的“编译”环境(这可是需要购买的)中加入了这样的工具 —— 到其他可以免费从 Internet 上下载的工具。

发现缺陷

当您准备运行代码并检查缺陷时,要记住往坏处想。这些缺陷是您所创建的或者由您忽略的代码产生。下面是一些帮助您找到代码中缺陷的提示:



  • 试着强行制造您所想到的所有错误条件并检查可以出现的所有错误消息。

  • 试着使用与其他组件或者程序交互的代码路径。如果其他程序或者组件还不存在,那么就自己编写一些脚手架代码以使您可以试用 API 或者填充共享内存、共享队列,等等。并让您的功能测试小组可以使用这个脚手架代码,这样他们就可以把它加入到他们的武器库中。

  • 对于 GUI 中的每一个输入字段,试验下面多种不同的组合(考虑 自动化):



    • 不可接受的字符(控制字符、非打印字符等)。

    • 过多的字符。

    • 过少的字符。

    • 负数(特别是当您只期待正数时)。

    • 过大和/或者过小的数。

    • 剪切和粘贴数据和文本到输入字段,特别是当您编写的代码限制用户可以键入该字段的内容时。

    • 文本和数字的组合。

    • 全大写字母和全小写字母。




  • 为代码创建“压力条件”,如大量活动、慢连接的网络和所有您想到的可以将代码推到极限条件的东西。

  • 反复进行同样的步骤,然后:

    • 检查未预计到的内存损失条件。

    • 检查当内存用光时发生什么。

    • 试图创建缓存溢出、满队列、不可用的缓存以及其他“不能正确工作”的情况。




  • 对于数组和缓存,试着向数组(或者缓存)增加 n 个数据项,然后试图删除 n+1

    个项。


关于时间的考虑?

如果操作“b”在操作“a”之前发生会怎么样?就算您 认为 它不会发生 —— 您能 使 它发生吗?如果是的话,可以打赌您的客户会使它发生的。最好现在找出来,而不是在修复成本更高、并听到客户报怨您的软件质量糟糕之后再去做。

脚手架代码

我们在前面 发现缺陷 中讨论了脚手架代码。如果是为自己的使用需要而创建的,一定要将它交给验证工程师。可能您提供的脚手架代码使他们可以很快地开始测试您的代码,或者至少使他们更好地理解当其他组件存在时可以预期什么。

如果您的产品有保护性的安全功能,那么您必须测试它们。提供可以创建您想要防止的情况的脚手架代码是很重要的:您必须能够创建系统试图防止的那种情况。

脚手架代码的另一个简单例子是提供操纵队列的代码。如果您的产品使用队列,那么想像如果有一个可以在运行时从队列中增加或者删除项、破坏队列中的数据(以保证适当的错误处理)等等的工具会有多方便。

源代码级调试程序

使用源代码级的调试程序是进行彻底和成功的单元测试的关键方法。开发人员应该与他们的调试程序共生死。不幸的是,对源代码级的调试程序的充分了解和使用是一种正在消亡的做法,尽管这些调试程序的好处远远超过任何学习曲线。简而言之,我们强烈鼓励您全面学习一种调试程序。下面是用源代码级调试程序对代码进行单元测试的几种方法。您可以:

  • 在运行中操纵数据 —— 例如,在输入代码时设置中断点,然后重新设置传递的参数值以检查代码是否能正确处理(现在为)无效的参数。以这种方式使用调试程序就不需要让错误条件真正发生。

  • 设置断点,然后“单步”通过代码,这样您就可以看到每一行代码所做的事情。

  • 设置对变量的“监视(watch)”。

  • 强制使用错误代码路径。

  • 观察调用堆栈以检查哪一个例程调用了您的代码。

  • 在错误发生时“捕获”它们。

  • 执行边界检查。


认识您的验证工程师

验证工程师是测试知识的很好来源。他们可以给您指出要测试什么并帮助您了解可以在代码中加入什么以帮助他们测试(如代码钩子)。此外,您可以向他们展示如何使用您的脚手架代码。他们还会很有兴趣了解您认为在测试中哪些应该是自动化的 —— 如果您某些事情做了不止一遍,那么他们也会。

开始测验!

现在是进行小测试的时候了。让我们看看您是否用心了。

问题

您希望检查一个整数的值是否为 5。通常,要这样编写代码:



不过,如果您对代码进行“手指检查”,并且把代码写成了下面这样会出现什么情况呢?



这个失误是一个缺陷,但是只有在运行时才能捕获它 —— 可能需要相当的调试努力才能找到它。编译器会轻易放过您的代码,那么如何防止这种错误发生?

答案

实际上有两个答案:您可以使用一种上面描述的静态代码分析工具,并希望它有足够的健壮性可以捕获这种错误,也可以交换操作数以使常量位于左边:



因为这种方法保证您可以在编译代码时立即捕捉到问题,所以它是首选的技术。虽然它看上去有些笨,但是代码可以编译并运行得很好。然而,当您“手指检查”代码时就可以立即看到好处了:



可是编译器不喜欢这样,因为 5 不能被赋值为另一个值。这就是我们在 前面 说您应当将编译器看成是您的朋友时所表达的意思。

您还可以在检查 null 指针时使用这个技巧。看下面的代码:



如果您偶然将它“误写”成下面这样会发生什么呢?



您可能不会得到想要的结果。而改用下面的方法您会得到与我们刚描述过的同样的“编译器保护”:



结束语

为保持简明扼要我们做了一个相当简洁的归纳:要么现在去做,要么以后花 多得多 的代价去做。换句话说,您在开发周期的早期在测试和预防代码缺陷上花的时间越多,您在以后节省的时间和金钱就越多。这就是防御性编码的意义。它就是这么简单。

自己用VC来做自己的专业安装程序

由于上次的巨大损失,关于本篇的几百字说明全部化为一片泡影。下次有时间我一定花时间来恢复,现在先只提供下载和预览。:~~~( 嘻嘻:)我这人太懒了,同样的事情最多只能做一遍,要我多做一遍,简直就是要偶的...
  • tlovexyj
  • tlovexyj
  • 2001-02-12 14:58:00
  • 1520

防御性编码和单元测试规则(一)

开发人员编写代码。不幸的是,开发人员也编写缺陷,其中大多数缺陷是在最初的编码阶段加入的。修复这些缺陷成本最低的地方同样也是在开发的初始阶段。如果等到功能测试或者系统测试来捕获并修复缺陷,那么您的软件开...
  • chensheng913
  • chensheng913
  • 2004-08-10 23:49:00
  • 6327

防御性编码有助于快速定位问题

利用防御性编码,对不符合前置条件的情况进行快速反馈,对可以预见到的陷阱进行主动防守,通过明确的预期行为来代替运行时的不确定性,可以为问题跟踪带来非常大的便利,提升开发效率。...
  • caowenbin
  • caowenbin
  • 2015-01-07 19:53:49
  • 2394

防御性编程技巧

在防御性编程的大框架之下,有许多常识性的规则。人们在想到防御性编程的时候,通常都会想到“断言”,这没有错。我们将在后面对此进行讨论。但是,还是有一些简单的编程习惯可以极大地提高代码的安全性。尽管看上去...
  • everpenny
  • everpenny
  • 2011-04-11 22:06:00
  • 4015

QR码编码原理二(编码)

申明,本文非笔者原创,原文转载自:http://blog.csdn.net/dekko/article/details/6122239...
  • carson2005
  • carson2005
  • 2014-07-07 14:49:40
  • 2395

聊聊单元测试(二)——MockEJB

Enterprise JavaBean (EJB)是J2EE应用程序中的重要构件块,它为开发人员提供了一个支持服务定义、事件驱动处理和对象-关系持久性的标准框架。但是,使用EJB的开发 人员经常抱怨,...
  • shan9liang
  • shan9liang
  • 2014-07-14 11:10:19
  • 2159

EAS BOS根据编码规则生成编码

ICodingRule codingRule = CodingRuleFactory.getLocalInstance(ctx); ICodingRuleManager codingRuleMana...
  • sjp_87
  • sjp_87
  • 2015-10-28 18:08:44
  • 825

防御性驾驶技术全集详细技巧-什么是防御性驾驶

防御性驾驶技术是将相关的驾驶技能和驾驶习惯进行系统的总结和归纳,形成一套简单明了、科学系统的安全驾驶体系,它能帮助驾驶员更清楚地了解人类的“生理缺陷”;更全面地观察并了解驾驶环境;更准确地预测不确定的...
  • kwame211
  • kwame211
  • 2017-09-13 09:07:19
  • 261

单元测试设计原则

背景 为了提高开发人员的代码质量,编写高质量的单元测试,要遵守3R(Responsible, Reliable, Repeative)原则,具体含义如下: Responsible: 谁开发...
  • heymysweetheart
  • heymysweetheart
  • 2016-07-06 10:11:21
  • 1254

几种常用的编码(十进制代码)

十进制代码   为了用二进制代码表示十进制数的0-9这十个状态,二进制代码至少应当有4位。4位二进制代码一共有十六个(0000-1111),取其中哪十个以及如何与0-9相对应,有许多种方案。下表中列出...
  • chunxiaoyuye
  • chunxiaoyuye
  • 2016-03-11 23:02:11
  • 1342
收藏助手
不良信息举报
您举报文章:防御性编码和单元测试规则(二)
举报原因:
原因补充:

(最多只允许输入30个字)