追求代码质量 - 通过测试分类实现敏捷构建2010-12-12 IBM Andrew Glover如果这样说不会(令您)很痛苦的话,请设想您是一名任职于一家 2002 年 早期创建的公司的开发人员。在金钱的驱动下,您和您的团队接到了一项任务, 即使用最新且最强大的 Java™ API 构建一个大型的数据驱动的 Web 应用 程序。您和公司管理层都坚定不疑地相信这就是最终将被称为敏捷过程 的东西 。从第一天起,您就用 JUnit 构建测试,且把它作为 Ant 构建过程的一部分尽 可能频繁地运行。还将设置一个定时任务在夜间运行构建。在接下来的某个时刻 ,有人会下载 CruiseControl,不断增长的测试套件会在每次签入时运行。时至今日经过过去几年的努力,您的公司已经开发了一个庞大的 代码库和一个同样庞大的 JUnit 测试套件。一切都很正常,直到大约一年前, 测试套件包含了 2000 个测试,同时人们开始注意到运行构建过程用时超过三个 小时。在此之前的几个月,由于 CI 服务器资源紧张,您在代码签入时通过 Continuous Integration(CI)停止运行单元测试,并将测试切换到夜间运行, 这使得之后的早晨时间非常紧张,于是开发人员努力去弄清楚是什么出错以及为 什么出错。这些天,似乎测试套件整晚极少超过一次运行,为什么会这样呢?因为它们 费时太多!没人会仅仅为了弄明白系统是否运行良好而几个小时守在那里。此外 ,整个测试套件都是在晚上运行,不是吗?由于测试运行得太不频繁, 它们常常充满了错误。因而,您和您的团队开始质疑单元测试的价值:如果它们 对代码质量那么重要,那又为什么会让人这么头痛呢?你们的结论是:单元测试 有其重要的作用,但必须要能用一种更为敏捷的方式运行它们。尝试测 试分类您所需要的是一个将构建转换到一种更为敏捷状态的策略。您需要这样一种 解决方案,使一天当中运行测试的次数超过一次,并使测试套件恢复到要用三个 小时才能完成构建之前的水平。为完整地恢复整个测试套件,在试图提出一个策略之前,很有必要弄清楚通 用术语 “单元测试” 的含义。诸如 “我家有一个动物” 和 “我喜欢车” 这 样的表述并不很具体,“我们编写单元测试” 也是一样。这年头,单元测试能 代表一切。就拿之前有关动物和车的表述来说:它们导致了更多的疑问。例如,您家有 哪种动物?是一只猫、一条蜥蜴还是一头熊?“我家有一头熊” 和 “我家有一 只猫” 截然不同。同样,当和汽车销售员交谈时,只说 “我喜欢车” 没什么 用处。您喜欢哪种车:赛车、卡车还是旅行车?任何一个答案都能带来截然不同 的结果。同样,对于开发人员测试来说,按照类型 将测试分类也是很有用的。这样做 能够实现更为精确的语言,并且能使您的团队以不同的频率运行不同的测试类型 。为了避免运行所有 “单元测试” 所需的令人恐惧的三小时构建时间,分类是 关键。三种类型测试套件可以形象地分为三层,每一层代表一种不同的人员测试类型, 该测试类型由其运行时间的长短决定。正如在图 1 中看到的那样,每一层都增 加了总的构建时间,要么增加了运行时间,要么最终增加了编写时间。图 1.测试分类的三个层次

底层由运行时间最短的测试构成,可以想象的到,它们也最易于编写。这些 测试占用的代码量也是最少的。顶层由更高级别的测试构成,这些测试占用了应 用程序更大的部分。这些测试有一点难于编写,执行时间也要长得多。中间层是 处于这两个极端中间的测试类型。三种类型如下所示:单元测试组件测试系统测试