易于测试的代码

发表于:2014-5-06 11:32

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

 作者:大力(金风)    来源:51Testing软件测试网采编

  软件IC是人们在讨论可复用性和基于组件的开发时最喜欢使用的比喻。意思是软件组件应该就像集成电路一样进行组合,这只有在你使用的组件已知是可靠地时候才能行之有效。
  芯片在设计时就考虑了测试——不只是在工厂,在安装时,而且也是在部署现场进行测试。更加复杂的芯片和系统可能还拥有完整的Built-In-SelfTest(BIST)特性,用于在内部运行某种基础级的诊断;或是拥有Test Access Mechanism(TAM),用以提供一种测试装备,允许外部环境提供激励,并收集来自芯片的响应。
  我们可以在软件中做同样的事情,与我们的硬件同事一样,我们也需要从一开始就把可测试性(testability)构建进软件中,并且在把各个部分连接在一起之前对每个部分进行彻底的测试。
  单元测试
  硬件的芯片级测试大致等价于软件中的单元测试(unit testing)——在隔离状态下对每个模块进行测试,目的是检验其行为。一旦我们在受控的(甚至是人为的)条件下对模块进行了彻底的测试,我们就能够更好地了解模块在广阔的世界上将怎样起反应。
  软件的单元测试时对模块进行演练的代码。在典型情况下,单元测试将建立某种人工环境,然后调用被测试模块中的例程。然后,它根据已知的值,或是同一测试先前返回的结果(回归测试),对返回的结果进行检查。
  随后,当我们把我们的“软件IC”装配进完整系统中时,我们将有信心,各个部分都能够如预期的那样工作,然后我们可以使用同样的单元测试设施把系统当做整体进行测试。
  但是,在我们走那么远之前,我们需要决定在单元级测试什么,在典型情况下,程序员会随便把一些数据扔给代码,就说已经测试过了,应用“按合约设计”后面的思想,我们可以做得好得多。
  针对合约进行测试
  我们喜欢把单元测试视为针对合约的测试。我们想要编写测试用例,确保给定的单元遵守其合约。这将告诉我们两件事情:代码是否符合合约,以及合约的含义是否与我们所认为的一样。我们想要通过广泛的测试用例与边界条件,测试模块是否实现了它允诺的功能。
  我们为什么要这么费事?最重要的是,我们不想制造“定时炸弹”——呆在周围不被人注意,却在项目最后的尴尬时刻爆炸的东西。通过强调针对合约进行测试,我们可以设法尽可能多的避免那些“下游的灾难”(downstream disaster)。
  提示
  Design to Test 为测试而设计
  当你设计模块,或是单个例程时,你应该既设计其合约,也设计测试改合约的代码。通过设计能够通过测试,并履行其合约的代码,你可以仔细地考虑边界条件和其他非如此不会发现的问题。没有什么修正错误的方法比一开始就避免发生错误更好。事实上,通过在你实现代码之前构建测试,你必须在你确定采用某个接口之前先对它就行试验。
  编写单元测试
  模块的单元测试不应被扔在源码树的某个遥远的角落里。他们须放置在方便的地方。对于小型项目,你可以把模块的单元测试嵌入在模块自身里。对于更大的项目,我们建议你把每个测试都放进一个子目录。不管是哪种方法,要记住,如果你不容易找到它,也就不会使用它。
  通过使测试代码易于找到,你是在给使用你代码的开发者提供两样 无价的资源:
  1. 一些例子,说明怎样使用你的模块的所有功能。
  2. 用以构建回归测试,以验证未来对代码的任何改动是否正确的一种手段。
  让各个类或模块包含自己的单元测试很方便(但却并非总是可行)。例如,在Java中,每个类都有自己的main,除了在应用的主类文件里,所有的main例程都可用于运行单元测试,当应用者自身运行时它将被忽略。这样做的好处是,你交付的代码仍然含有测试,可用于在现场对问题进行诊断。
  在C++中,通过使用#ifdef有选择的编译单元测试,你可以(在编译时)获得同样的效果。
  但是只提供单元测试还不够,你还必须运行它们,并且经常运行它们,如果类偶尔通过了测试,那也是有帮助的。
21/212>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

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

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

沪ICP备05003035号

沪公网安备 31010102002173号