用Visual Studio实践敏捷测试 (一)下
在开发人员实现设计的同时制定测试计划
当项目经理、开发、测试三方的负责人都同意并在用户故事上签字[1]之后,开发人员就会着手设计并实现功能,那么此时测试人员应该做些什么呢?不同于传统开发模式时那样需要等待一个可测试的版本,敏捷软件开发中的测试人员应该尽早制定测试计划,并与负责的开发人员交流,让他/她了解你将实施什么样的测试。为什么?这里有两个理由,我在前面其实也都提到过了。一是合理利用有限的资源,二是尽早发现问题。软件开发中一直有这样的理论:bug在开发周期的越早被修复,付出的代价就越低。比如,我们强调审阅用户故事,将错误扼杀在代码写成之前,这几乎是没有代价的。而此时,尽可能早的将测试计划于开发人员分享也是同样道理:开发人员在编程时可能没有想得十分全面,通过参考你的测试计划,也许会直接发现他设计中的问题,也许可以在调试的时候顺便尝试某些不太有把握的用户场景。这样,你再一次成功阻止了bug的出现。而且因为开发人员在把代码发出来给别人审阅之前就修复了它们,这同样是一种几乎不用付出代价的修复的情况。所以说,在开发人员编写代码的时候,测试人员应该抓紧时间,争取尽可能早的把测试计划制定出来与开发人员分享!
从另外一方面来说,尽早分享测试计划不仅有助于开发人员尽早发现问题,同样也有助于测试人员发现测试计划中的问题。谁能保证测试计划本身没问题呢?开发人员更了解代码是如何实现的,他/她可以提供许多有用的信息:某些测试可能是不必要的,因为他/她实现该功能的方式不存在类似问题;某些测试期待的结果可能是不合理的,因为在他/她的设计中正确的行为应该是另一个样子;应该加强某一部分的测试,因为他/她觉得这部分逻辑很复杂,出错的可能性比较大……开发人员可以为我们提供很多有用的反馈意见以完善我们的测试计划。因此,尽早将你的测试计划与开发人员交流,是一件双赢的事情。
接下来,我想和大家分享一下我们的团队是如何制定、管理我们的测试计划的。首先,我们对于每一个用户故事,都需要定义两类测试:验收测试和功能测试。验收测试从字面上很容易理解:用户故事通过了这些测试,我们就认为它达到了“完成”的验收标准。换句话说,就是我们可以认为该功能已经实现了,虽然还可能有各种bug,但是基本功能可用。所以,通常验收测试只针对该用户故事最基本的功能、最常见的用户操作流程,其目的是确保最基本的功能可以工作。验收测试的另一个特点是通常会是一个完整的针对该故事的操作流程,数据也是比较接近真实情况下的数据,这样才更符合它存在的意义——保证基本功能可以工作。当然,我们都知道一个功能不是只满足最基本的用法就可以的,用户可能会用其他的操作流程,会用一些边界数据,这就需要更多的功能测试来弥补这些细节。区别于验收测试的流程化,功能测试通常都是针对用户故事中的某一个细节,比如某一个输入变量的值,反复测试各种可能,数据也要求尽可能广泛的覆盖更多不同类型。一般来说,一个用户故事只需要1~2个验收测试,功能测试却可能数量非常庞大。除了这两种最基本类型的测试外,我们还会根据用户故事的具体情况,添加一些其他的测试,比如对于那些需要处理大量数据的功能,添加一些压力测试、性能测试就是十分有必要的。
在制定测试计划时,我们通常会先在OneNote中把初步的测试想法写好,发给团队成员审阅、讨论。这一过程与审阅用户故事十分类似,优点也大同小异。在讨论结束后,我们会整理出一份测试计划输入到TFS数据库中去,以方便管理。同时我们还会把验收测试的流程写到OneNote页面的用户故事下面,这样做的目的是提醒开发人员至少要满足什么样的条件才能通过验收,毕竟开发人员不会时常查看测试计划,却需要时常访问具体描述功能的OneNote页面。
我们使用Visual Studio 2010中的Microsoft Test Manager工具来管理我们储存在TFS中的测试计划和具体测试用例(测试用例也是2010版本中新添加的工作项类型),这样做的优点是团队成员可以很容易的共享这些信息。在这里,我们不但可以方便的编辑、管理测试计划和测试用例,还可以运行测试用例、分析运行结果、提交bug等。这里我主要介绍一下测试计划和测试用例的管理——创建测试计划、为测试计划指定测试环境(操作系统、浏览器等等)、创建测试用例以及将测试用例分门别类。至于其他功能,在本文后面的章节涉及到时我会再做介绍。下图展示的是一个测试计划:
图 1 测试计划
我们可以看到该测试计划中指定了测试的环境为“Vista+IE7”(你也可以配置多组不同的环境,甚至可以为不同的测试用例或分类指定不同的环境),其下包含了多个测试用例集:
- 用户故事相关的测试用例集
- 单元测试用例集
- 验收测试用例集
- 功能测试用例集
- 性能测试用例集
- 压力测试用例集
- 手动测试用例集
- 自动化测试用例集
测试用例被分类至各个测试用例集,结构十分清晰。这里需要注意的一点是,测试用例只是逻辑上从属于某个测试用例集,并没有物理从属关系,即一个测试用例可以同时被分在多个测试用例集内,比如某个测试用例性质上是一个性能测试,但是由于该用户故事的诉求就是性能改进,我们也就很自然得可以将其作为该用户故事的验收测试,此时我们就可以将此测试用例添加到验收测试和性能测试两个测试用例集中;另一个例子是我们给每个用户故事都定义了不少测试,这些测试用例都应该能在用户故事测试用例集下找到,但是这些测试既可能是手动测试也可能是自动化测试用例,所以它们又会被本别归类至这两个测试用例集。在这种逻辑分类的支持下,我们可以很容易的根据需要指定运行测试集中一部分测试用例。比如,我们可以定义一个签入测试的测试用例集,挑选最基本的若干个测试置入其中,这样在每次签入前通过运行这个测试用例集就能帮助我们确保签入的代码不至于破坏最基本的功能,即保证了版本随时可运行可测试,这无疑为测试带来了更多的方便。具体如何创建测试用例集的结构,团队可以根据自己项目的特点,灵活运用此功能,制定分类规则以提高工作的效率。
下面让我们进一步来看一下测试用例:
图 2 测试用例
如果你对TFS工作项有所了解,就不难发现测试用例的形式与常见的bug、任务等工作项十分类似。不错,测试用例正是Visual Studio 2010中新加入的一种工作项类型。它包括工作项通用的一些字段,比如标题、优先级、状态……我就不多作解释了,这里重点介绍测试用例工作项的几个特殊字段:
- 测试步骤(Steps) :这是测试用例工作项最核心的字段。我们使用这个字段可以定义测试用例的每一个具体步骤、预期的结果,还可以通过附件对结果进行详细说明。另外,Visual Studio 2010中还提供了一种名为共享步骤( Shared Steps) 的工作项,我们可以将测试用例中重复的步骤提取出来,创建一个共享步骤,再将其作为一步添加到测试步骤字段中,以达到在多个测试用例中复用这些步骤的目的。
- 参数值(Parameter Values) :有的测试计划中多变的不是测试步骤本身,而是通过不同的输入数据来测试不同的情况。测试用例工作项也为此提供了支持,在测试步骤的下方还有一个参数值区域,可以定义多组输入/输出数据。
- 测试的用户故事(Tested User Stories): 提供了从测试用例到用户故事的反向连接。在需要理解测试用例的设计用意时,十分有用。
- 关联的自动化测试(Associated Automation): 可以将自动化测试与测试用例关联起来。
图 3 共享步骤
小结
以上介绍的是测试人员在正式进入测试阶段之前的一些“测试准备”工作,可能与传统意义上的测试任务有所不同,不过却是十分重要的,其作用表现在:
- 加强了团队整体的交流和合作
- 保证了产品在进入测试阶段时就能有较好的质量
- 为开发人员修复bug乃至整个Sprint的完成节省了时间
从下一篇起我们将开始讨论实际的测试过程,则会与一般的测试经验比较接近。
[1]这里的负责人并不是指团队经理等负责人,而是我们会给每一个用户故事指定三方各一个团队成员来负责,这样做的好处是当需要查询关于某一个用户故事的进度、设计、功能等问题时很容易就能找到负责的人了解情况。
作者:林俊彦,复旦大学计算机专业毕业后加入微软,现为微软亚太研发集团服务器与开发工具事业部(中国)的软件测试开发工程师,参与了Visual Studio及.NET Framework多个版本的开发测试工作。林俊彦还参与了《Visual Studio DSL工具特点领域开发指南》、《为软的软件测试之道》等书籍的中文翻译工作。
本文精简版收录于《程序员》6月刊。