摘要:编写优良的测试程序,可以极大提高编程速度,即使不进行重构也一样。
请构筑一个良好的bug检测器,并经常运行它,对任何开发工作都大有裨益,这是重构的前提。
自测试代码的价值
- 类应该包含自己的测试代码。每个类都应该有一个测试函数,用来测试自己这个类
- 确保所有测试都完全自动化,让它们检查自己的测试结果:将所期望的输出放进测试代码中,然后做出一个比较,可避免人工检测
- 可以在每次编译之后都进行测试,可以大大提高生产性能
- 构筑的类能够自我测试&&可频繁运行测试
- 编写测试代码的时机:
- 最有用:在开始编程之前,当需要添加特性的时候,先写相应测试代码
- 编写测试代码,就是回答此功能需要做些什么
- 使你把注意力集中于接口而非实现
- 为工作安上一个明确的结束标志,一旦测试代码正常运行,工作就结束了
- 最有用:在开始编程之前,当需要添加特性的时候,先写相应测试代码
- 极限编程:频繁测试是其重要一环。极限编程者都是十分专注的测试者。它们希望尽可能快速开发软件,也知道测试可让他们尽可能快速地前进
- 重构:必须编写测试代码。
- 方式:
- testing main:惯用手法。每个类都应该有一个用于测试的main()。这是一个合理的习惯,但可能不好操控。问题:很难轻松运行多个测试
- 建立一个独立类用于测试,并在一个框架中运行它,使测试工作更轻松
junit测试框架
- 框架简单,却可以让你进行测试所需的所有事情
- assert():扮演自动测试角色
- 建议:
- 频繁运行测试。每次编译,请将测试也考虑进去,每天至少执行每个测试一次
- 重构过程中,可以只运行少数几项测试,主要用来检查当下正在开发、整理的代码
- 测试机制可以运行,的确测试了它该测试的东西(断言的合理使用)
- 功能:捕捉失败&&捕捉错误异常。出现形式不同,排除过程也不同
单元测试
- 目的:提高程序员的生产率
- 高度局部化的东西,每个测试类都隶属于单一包
- 能够测试其他包的接口。除此以外,将假设其他包一切正常
- 重构时,更多地依赖单元测试
功能测试
- 保证软件能正常运作。
- 从客户角度保证质量,并不关心程序员的生产力。
- 应该由一个喜欢寻找bug的独立团队开发,且应使用重量级工具、技术来帮助自己开发良好的功能测试
- 一般,尽可能将整个系统当作一个黑箱。只观察特定输入导致的数据变化
- 功能测试,往往以其他工具辅助进行
- 一旦发现错误:
- 修改代码,排除错误
- 添加一个单元测试,暴露bug
- 每当收到bug报告,都应先编写一个单元测试,使bug浮现出来。如果出现其他相关失败,编写更多的测试。用单元测试来盯住bug,并确保单元测试不会由漏网之鱼
添加更多测试
- 观察类该做的所有事情,针对任何一项功能的任何一种可能失败的情况,进行测试。不仅仅是测试所有public函数
- 测试是一种风险驱动的行为。测试的目的是希望找出现在、未来可能出现的错误。=》不会去测试那些仅仅读、写一个字段的访问函数,太简单,不太可能出错
- 注意:撰写过多测试,结果往往测试量反而不够。
- 哪怕只做一点点测试,你也可从中受益
- 测试要诀:测试你最担心出错的部分,才能从测试工作中得到最大利益。
- 编写未臻完善的测试并运行,好过对完美测试的无尽等待
- 测试技巧:
- 寻找边界条件
- 考虑可能出错的边界条件,将测试火力集中在那儿
- 包括寻找特殊的、可能导致测试失败的情况。文件相关的:第一个字符、最后一个字符、空文件……
- 测试扮演“程序公敌”的角色。积极思考如何破坏代码。这种思考可以提高生产力。
- 检查预期的错误是否如期出现。例如,关闭文件流后,再次读取。
- 当事情被认为应该出错时,别忘记检查是否抛出了预期的异常。
- 测试类愈来愈多,可以生成另外一个类,专门包含由其他测试类所组成的测试套件,以便拥有一个主控的“测试类
- 寻找边界条件
- 任何测试都不能证明一个程序没有bug。但一旦重构,可以更好地理解整个程序,从而找出更多bug
- 不要因为测试无法不着所有bug就不写测试,测试的确可以捕捉大多数bug
- 测试可以提高编程速度。其目的都是保证你能够测试所有情况的一切组合
- 应该把测试集中在可能出错的地方。观察代码,看哪儿复杂?观察函数,看哪儿可能出错?
- 当测试数量到达一定程度之后,继续增加测试带来的效益会曾宪递减事态,而非持续递增;如果试图编写太多测试,可能会因工作量太大而气馁,最后什么也写不成;
面向对象的测试
- 继承、多态会让测试变得比较困难。=》将有很多组合需要测试
- 不总时测试所有可能组合。尽量测试每个类,可以大大减少各种组合所造成的风险。
- “花合理的时间抓出大多数bug”,好过“穷尽一生抓出所有bug”
测试代码
- 与产品代码之间的区别:可以放心复制、编辑测试代码