需求与测试用例,特别是验收测试,是密切相关的。敏捷方法本身基于测试驱动方法,尤其强调这一点。可以增强 UML 用例的符号以使增强后的 UML 工具可以正确地处理用例与测试之间连接。
验收测试是设计的一部分
"测试驱动开发"或 Dan North 观点里的"行为驱动开发"是敏捷范式里最好的实践之一。当我第一次读到 BDD 的介绍时,对文字模板的"可执行规格"概念的印象特别深刻:
(T1) Given <context> {and <context>}, when <event>, then <outcome> {and <outcome>}
“可执行规格”,多好的想法!不管在所有环境中这一概念的可用性情况,比如很难想象如何按字面意义将它应用到一个合同文档中,但是它作为隐含信息却改变了我看待测试的方式:
- 验收测试是设计的一部分!
为什么仅仅是验收测试?单元测试、集成测试、系统测试又怎样呢?
- 单元测试通常用于检测低层构件,如类方法,它们受很多实现决策的限制,以至于需要认真地考虑:我没见过将单元测试作为设计组件,但可作为辅助从源代码中用工具自动生成。
- 系统(或子系统)测试用于检测高层组件交付时的准备状态,所以我将系统测试看作验收测试。
- 集成测试提出了问题:我的简单回答是它应该被看作验收测试。或者"应该"这个词需要更深的认识,它牵涉到"黑盒测试"和"白盒测试"。"黑盒测试"聚焦于系统做什么,"白盒测试"则聚焦于系统如何做。"白盒测试"类别中多一个测试失败,则离"验收"的类别更远。换句话说"黑盒测试"类别中多一个集成测试失败,离"验收"类别就更近了。
一些敏捷方法,包括 XP(eXtreme Programming)和 Scrum 在内,建议将用户故事作为需求的产出。一些作者,例如 Mike Cohn 或 Scott Ambler ,认为用户故事如果简洁,则特别高效。并且,笼统地提议采用以下模板 5:
(T2) As a <role>, I want to <goal/desire>, so that <benefit>
第一印象是"so that"子句是可选的 6,但 Chris Matts7 觉得它是提出以下模板的基础:
(T3) In order to <receive benefit> as a <role>, I want to <goal/desire>
我的观点是接受 Chris 的论点且认为"in order to"子句或相同的"so that"是关键。事实上,我认为任何需求都需要至少一个验收测试和这样一些子句,它们应该用于沟通验收测试的期望: <goal/desire> 表明测试的产出应该符合
在一个同时管理用户故事和验收测试的假想的工具中,每个验收测试应该链接到一个特定用户故事的"so that"子句,而不是直接链接到用户故事。
正好说到点子上,我的用户故事模板的愿景是:
(T4) As a <role>, I want to <goal/desire>, so that <benefit> {and <benefit>}
每个"benefit",而非完整的"so that"子句,都应该有至少一个相关的验收测试。
UML 用例与验收测试
我想知道同样的概念是否可以通过 UML 用例图表达。在这篇文章中"用例"应该总是解释为"UML 用例图"或"UML 用例工件",我避免使用用例描述的原因是它们与 UML 相比既有期望的特性也有不期望的特性。我的目标是呈现一个十分合适 UML 图的想法。
图 1 中高亮显示的是一个用户故事的一个部分与用例图之的双向连接:"As a
图 1 : 用户故事与 UML 用例间的关联
UML 用例产出并不能严谨地表达"so that"子句,而只能用注释的方式介绍它(如图而):
图 2 : 用户故事与 UML 用例间的关联
在这里,UML 用例比用户故事的表现力更差:同时管理 UML 用例和验收测试的假想工具被强迫连接一个验收测试和一个用例,就像连接一个主元素(验收测试)和一个辅助元素(评论)一样在逻辑上是错误的,并且应该受到禁止。
如果 UML 用例工件允许将验收测试定义成其工件的一部分,那么情况就很不同了。我认为验收测试之于用例相当于方法之于类(如图 3)。
图 3 : 验收测试之于 UML 用例相当于方法之于类
明显,我滥用了 UML 符号来解析我的愿景。
简单和复杂需求
需求可以被划分成两类:简单需求和复杂需求。一个简单的需求只包括单一的业务功能,但一个复杂的需求则包括多个业务功能。单一功能不一定只关联到单一的 UML 用例,而通过内含(included)用例和扩展(extended)用例修饰的主用例不一定要当作复杂需求。下面通过一个例子来澄清二者的区别。
假设你有以下的干系人的请求:
(SR-1) 系统要通过添加、更新、获取条目来管理产品列表。
可以通过图 4 中的 UML 用例图来描绘,具体含有 5 个简单需求:
图 4 : 产品管理用例
你可以注意到,内含的"select product"用例并未算作简单需求。
假设你现在有以下干系人的请求:
(SR-2) 所有操作应该被日志记录以用于审核目的。
下面的天真的方法(如图 5)不能满足需求,那么实际上我们该如何定义验收测试呢?
图 5 : 对于复杂需求的天真方法
这一问题显示了强烈希望 UML 用例与验收测试耦合的原因之一:需求的最重要属性是可测试性,所以它对 UML 用例也是一样。
UML 符号允许定义抽象用例和指定的其它的用例,这使得你可画出如图 6 所示的别样的图。
图 6 : 抽象用例
这个图对于所有面向对象的专家异常清晰,而且容易向周围人解释。这里强调的是,"logged operation"用例的抽象本质决定其指派指定的具体用例来提供所需的验收测试。
留意我之前称作“简单需求”和“复杂需求”之间巨大差异:前者允许与测试间的直接链接,后者没有这种工具并且要依赖于其它特性。
问题是如何保证定义出所有的(验收)测试。
测试作为 UML 用例方法
下面我在图 7 中修改了图 6(这里再一次滥用了 UML 符号)。
图 7 : 测试作为用例方法
此前介绍的假想工具可以自动处理抽象"test logged operation",例如为所有具体派生用例生成需要的测试。注意,用例应能概括测试用例,但细化测试用例却不是它的责任:"use case test method"应该包括名称,可能包括输入参数,和模式(例如,inspection、demonstration、log analysis 等等)。
结论
我认为用户故事是收集干系人请求是一个很有价值的工具,但是它们要求更加详细的阐述以细化需求。此外,它们不完全适合于融入图形工具:因此它们将或多或少地相当于简单 UML 用例。UML 用例提供丰富的功能,而且尽管它们已经陈旧,它们仍然存在隐含的可能性:具有增强的空间。很多现代设计工具将其它图形添加到 UML 图形中以便支持需求、测试案例以及元素之间的某种可追溯性。我想更好的解决方案是使 UML 用例符号更强大,就如前面段落所描绘的一样:我仅看到将(验收)测试封装到 UML 用例中的优点,这也可能打开了介绍新 UML 分类符的门,包扩测试细节的"验收测试"。我将以重申我的观点来结束本文,我卑微的观点是,验收测试是设计的一部分,如同敏捷实践或含蓄或明确地声称的那样。在更完整的框架中,系统的定义——高质量的定义 - 符合以下等式"系统定义"="需求"+"架构"+"验收测试",但完整地解释这一等式就需要在写一篇文章了。
引用
- 关于行为驱动开发看这里或这里。
- 黑盒测试
- 白盒测试
- “黑盒“测试是一个功能测试的同义词,而“白盒”测试是指结构化测试:参见这个 例子
- 它由 Connextra 的一个团队于 2001 年开发。
- Mike Cohn 可能是首位建议该观点的人。
- 想了解这个作者,请阅读这篇文章。
- Alistair Cockburn 的讨论。
关于作者
Raul Rugiero是凯捷的一个企业软件工程师,在信息系统的生产和交付上有 20 多年经验。他曾在多个行业工作过,如公共行政管理、电信和近年来的航空与国防。Raul 曾担任和持续担任各种角色,他最喜爱的角色是软件架构师,现在他主要处理需求分析、架构设计、项目技术领导和任何合适的工作,甚至组件开发。他不是任何特定技术或方法论的粉丝,但他根据自己兴趣跟随各种技术及方法论的演化。
查看英文原文: A Proposal to Enhance the UML Notation
感谢马国耀对本文的审校。
给InfoQ 中文站投稿或者参与内容翻译工作,请邮件至 editors@cn.infoq.com 。也欢迎大家通过新浪微博( @InfoQ )或者腾讯微博( @InfoQ )关注我们,并与我们的编辑和其他读者朋友交流。
评论