没有什么东西能够一直准确地描述产品的功能了吗?答案:当然有,那是产品代码和测试用例。产品代码实现了产品功能,它一定是准确描述了产品的当前功能,但是由于各种编程技术,如:面向对象、抽象、设计模式、资源文件等等,使得产品代码很难简单地能读懂,往往是在知道产品功能的前提下去读代码,而不是反过来看代码来了解功能。好的代码会有详细的注释,但这里的注释是对实现代码的解释和备注,并不是对产品功能的描述。这里有一篇很老的博客 Reading Code Is Hard,介绍了如何能够使代码更可读一些编写技巧。
  那么只有测试用例了,测试也应该忠实反映了产品功能的,否则的话测试用例会执行失败。以往大家只是把测试用例当作测试用例而已,其实对测试用例的理解应该再上升到另一个高度,它应该是能够扮演产品描述文档的功能。这要求我们编写的测试用例足够详细、测试用例的组织要有调理、分主次,单靠Word、Excel或者OneNote这样通用的工具是远远无法完成的,需要更多专用的测试用例管理工具来辅助,例如 Visual Studio 2010引入Microsoft Test Manager。
  此外,对于自动化测试用例(无论是API或者UI级别的)而言,代码在编写上也应该有别产品代码编写风格,可读性和描述性应该是重点考虑的内容。在测试代码中,当然可以引入面向对象、设计模式等的设计思想,但是一定要适度使用,往往面向过程的编码方式更利于组织、阅读和描述。
  3. 单次投入成本和多次投入成本原则。
  与其说这是一条评判测试用例的原则,不如说它是一条思考问题的思维角度和原则。成本永远是任何项目进行决策时所要考虑的首要因素,项目中的测试也是如此,对成本的考虑也应该客观和全面的体现在测试的设计、执行和维护的整个阶段中。当你在测试中遇到一些左右为难的问题需要决策时,尝试着从成本角度去分析一下,也许会对你的决策有所帮助。
  测试中的成本按其时间跨度可以分为:单次投入成本和多次投入成本。例如:编写测试用例可以看作是单次投入成本,因为编写测试用例一般是在测试的计划阶段进行(Scrum每个Sprint的开始阶段)的,虽然后期会有小的改动,但绝大多数是在一开始的设计阶段基本上成型了;自动化测试用例也是如此,它也属于是一次性投入;测试用例(包括:手工和自动化测试用例)的执行则是多次投入成本,因为每出一个新版本Build时都要执行所有的测试用例(或者进行BVT测试仅执行高优先级的测试用例)、分析测试结果、调试失败测试用例、确定测试用例的失败原因(产品缺陷、测试用例缺陷、测试框架缺陷还是随机问题导致了测试用例的失败),以验证该版本整体质量是否达到了指定的标准。
  之所有要引入单次和多次成本的思考,是希望能够通过区分测试中不同活动对测试成本的影响,从而进行帮助我们合理布局在不同阶段的投入和做出正确的决策,以保证在有限可负担测试成本的前提下,大限度地有效开展测试工作。例如,当我们意识到了,测试用例的设计和自动化属于是一次性投入,而测试用例的执行则是反复多次的投入时,应该积极思考如何能够提高需要反复投入的测试执行的效率,在一次投入和需要多次活动需要平衡时,优先考虑多次投入活动的效率,其实这里是有很多工作可以做。
  例如:第一条原则-单个用例覆盖小化原则 - 是一个很好的例子,测试A功能的3个功能点A1,A2和A3,从表面上看用Test_A1_A2_A3这一个用例在设计和自动化实现时简单的,但它在反复执行阶段会带来很多的问题:
  首先,这样的用例的失败分析相对复杂,你需要确认到底是哪一个功能点造成了测试失败;
  其次,自动化用例的调试更为复杂,如果是A3功能点的问题,你仍需要不断地走过A1和A2,然后才能到达A3,这增加了调试时间和复杂度;
  第三,步骤多的手工测试用例增加了手工执行的不确定性,步骤多的自动化用例增加了其自动执行的失败可能性,特别是那些基于UI自动化技术的用例;
  第四,(Last but not least)将不相关功能点耦合到一起,降低了尽早发现产品回归缺陷的可能性,这是测试工作的大忌。例如:如果Test_A1_A2_A3是一个自动测试用例,并按照A1->A2->A3的顺序来执行的,当A1存在Bug时,整个测试用例失败了,而A2和A3并未被测试执行到。如果此时A1的Bug由于某些原因需要很长时间才能修复,则Test_A1_A2_A3始终被认为是因为A1的Bug而失败的,而A2和A3则始终是没有被覆盖到,这里存在潜在的危险和漏洞。当你在产品要发布前终于修复了A1的Bug,并理所当然地认为Test_A1_A2_A3应该通过时,A2和A3的问题会在这时爆发出来,你不得不继续加班修复A2和A3的问题。不是危言耸听,当A2/A3的代码与A1的Bug修复相关时,当你有很多如此设计的测试用例时,问题可能会更糟… …,真的!:(
  综上所述,Test_A1_A2_A3这样的设计,减少地仅是一次性设计和自动化的投入,增加地却是需要多次投入的测试执行的负担和风险,所以需要决策时(事实上这种决策是经常发生的,尤其是在设计测试用例时)选择Test_A1_A2_A3还是Test_A1、Test_A2和Test_A3,请务必要考虑投入的代价。
  4. 使测试结果分析和调试简单化原则。
  这条原则是实际上是上一条- 单次投入成本和多次投入成本原则 - 针对自动化测试用例的扩展和延续。在编写自动化测试代码时,要重点考虑如何使得测试结果分析和测试调试更为简单,包括:用例日志、调试辅助信息输出等。因为测试用例的执行属于多次投入,测试人员要经常地去分析测试结果、调试测试用例,在这部分活动上的投入是相当可观的。有时候,测试框架提功能的一些辅助API等可以帮助很好实现这个原则。例如:Coded UI Test提供了类似的API,详见 - VS 2010 测试功能学习(18) – Coded UI Test三个必知的函数,来辅助基于Coded UI框架实现的自动化测试用例有更好的调试体验。
  测试理论为测试工作指明了大的前进方向,在实际工程中还需要我们不断地“活化”这些理论,使理论和实践更好的契合在一起。在我看来,软件工程项目不论成败和好坏,对我们每个参与者都是无比宝贵的。作为有心人,从中我们体会到很多书本上不曾提到过的东西,只要不断地去观察、体会和总结,你会有更多自己的认识、理解和发现。有很多人写书称赞,代码之美、测试之美,其实工程项目也是很美,只是看你能不能更客观地去看待它。