代码改变世界

用例指南

2007-09-10 20:41  澜心  阅读(400)  评论(0编辑  收藏  举报

用例
用例实例是系统执行的一系列动作,这些动作将生成特定主角可观测的结果值。

一个用例定义一组用例实例。
主题

解释 返回页首

以上定义中有几个关键词:

  • 用例实例。以上定义所说的序列实际上是贯穿整个系统的某个特定事件流,即一个实例。可能会有许多事件流,而许多事件流可能非常相似。为了使用例模型便于理解性,应该将相似的事件流组合到一个用例中。确定和说明某个用例实际上就是确定和说明一组相关的事件流。
  • 系统执行。这意味着系统提供用例。主角和系统的某个用例实例进行通信。
  • 可观测的结果值。您可以给一个成功执行的用例赋予一个值。用例应该确保主角可以执行某个具有可确定值的任务。确定用例的正确级别或粒度是非常重要的事情。正确级别是指所实现的用例不是太小。在某些特定的环境中,可以将一个用例当作组织内的一个计划单元,该单元包括了担任系统的主角角色的个人。
  • 动作。一个动作就是一个计算或算法过程。当主角向系统提供信号或当系统得到时间事件时,动作即被调用。动作可能包含向调用的主角或其他主角进行的信号传输。动作是不可分的,它要么完全执行,要么根本不执行。
  • 特定主角。主角是查找正确用例的关键,这尤其是因为主角可帮助您避开太大的用例。例如,考虑一个可视化建模工具。该应用程序有两个真正的主角:开发人员,他负责以该工具作为支持来进行系统开发;系统管理员,他负责管理该工具。这两个主角对系统都有各自的要求,因而需要自己的用例集。

系统的功能由不同的用例来定义,每个用例都代表了一个特定的事件流。用例说明将定义执行用例时在系统中发生的事件。

例如,在自动柜员机中,客户可以从帐户中提取现金、将现金转入帐户或核对帐户余额。这些功能对应于可以用用例来代表的事件流。

每个用例本身就有一个要执行的任务。所收集到的用例组成了所有可能的系统使用方法。只需注意一下用例任务的名称,就可以对该用例任务有一个大致的了解。

如何查找用例 返回页首

以下问题可以帮助您确定用例:

  • 对于已确定的各个主角,哪些任务会涉及到系统?
  • 是否需要将系统中发生的某些特定事件通知给此主角?
  • 此主角是否需要将突发变更或外部变更通知给系统?
  • 系统是否给业务提供了正确的行为?
  • 您已经确定的用例是否可以执行所有功能?
  • 哪些用例将支持和维护系统?
  • 在系统内应该修改或创建什么信息?

有些用例不代表系统的主要功能,因而通常会被忽略。这些用例可能属于以下类型:

  • 系统启动和停止。
  • 系统的维护。例如,添加新用户和建立用户简档。
  • 维护在系统中存储的数据。例如,所构建的系统和遗留系统平行工作,所以数据需要在两个系统之间达到同步。
  • 修改系统行为所需的功能。例如创建新报告的功能,它不仅可以创建硬代码,还可以对系统中存储的数据创建一组特定报告。

如果已经开发了业务用例模型和业务对象模型,另请参见指南:从业务模型到系统

用例如何演进 返回页首

在精化的早期迭代中,只对少数几个用例(在构架方面有重要意义的用例)进行比简要说明更为详细的说明。在深入到细节之前,通常应该先编写用例的提纲(按照分步格式)。此分步提纲应该是您定义用例事件流结构的首次尝试(请参见下文的事件流 - 结构)。始终要从基本的用例流开始。一旦对基本流提纲形成了一致意见,就可以添加与基本流相关的备选流内容。

当精化阶段即将结束时,应完成您计划要详细说明的所有用例。

是否详细说明了所有的用例? 返回页首

模型中通常会有一些简单的用例,它们不需要详细的事件流说明,对它们使用分步提纲就可以了。要作出这一决定,依据的标准是:您没有发现作为读者的用户对该用例的含义存在异议,而且设计人员和测试人员对于按分步格式提供的详细程度感到满意。这种简单用例的示例之一是描述简单的输入或从系统中检索某些数据的用例。

用例的范围 返回页首

通常很难判断一组系统交互或对话是否属于一个或几个用例。请考虑回收机的使用情况。客户将贮藏物品(如罐子、瓶子和箱子)插入回收机。当插入所有的贮藏物品后,她按下某个按钮,打印了一份收据。这样,她就可以用这一收据换取现金。

是否插入贮藏物品属于一个用例,而索取收据属于另一个用例?或者,以上过程只是一个用例?此过程有两个动作,缺少了任何一个,另一个动作都对客户没有任何意义。所以,应该将所有插入和获取收据当作一个完整对话,这样才对客户有意义。因而,从插入第一个贮藏物品到按下按钮获得收据的完整对话过程是一个完整的用例,也就是一个用例。

此外,最好将这两个动作连在一起,这样就可以同时对它们进行复审、修改、测试、为它们编写手册,并且在一般情况下将它们当作一个单元来管理。在大型系统中,明显需要这样处理。

用例如何实现 返回页首

用例可以说明当主角通过与系统交互来执行该用例时在系统中发生的事件。至于系统如何在内部利用协作对象来执行任务,用例并不加以定义。这将由用例实现来说明。

示例:

以打电话为示例,用例会说明以下内容:当呼叫方拿起听筒时,系统将发出一个信号,然后,系统会接收数字输入、查找接收方、使接收方的电话振铃、接通电话、传送语音等等。

在执行系统中,用例实例并不对应于实施模型中的任何特定对象(例如,代码中类的实例)。它所对应的是特定的事件流,该事件流由主角调用并且作为一组对象中的一个事件序列来执行。也就是说,用例实例对应于被实施对象的通信实例。我们将其称为用例的实现。通常,相同的对象会参与多个用例的实现。例如,银行业务系统中的“存款”用例和“取款”用例可能在它们的实现中同时使用某个特定的帐户对象。这并不表示这两个用例可以相互通信,它们只是在它们的用例实现中使用了相同的对象。

您可以认为一个事件流是由几个分支流构成的,这几个分支流组合到一起就形成了总的事件流。您还可以在其他用例的事件流中复用某个分支流的说明。一个用例事件流说明中的分支流可能是其他用例事件流说明中所共有的分支流。在进行设计时,应该让相同的对象来执行全部相关用例所共有的行为;也就是说,无论正在执行哪个用例,只应该有一组对象执行来这一行为。

示例:

在自动取款机系统中,“取款”用例和“核对余额”用例的事件流中的初始分支流是相同的。这两个用例的事件流都从检查卡标识和客户的个人访问代码开始。

一个用例具有许多可能的实例 返回页首

一个用例实例几乎可以遵循无限多的路径,但这些路径仍然可以计数。路径代表了用例事件流说明中的用例实例可以选择的各种方案。路径的选择取决于事件。事件类型包括:

  • 来自主角的输入。例如,主角可以从几个选项中决定下一步应该做什么。

示例:

在回收机系统的“回收贮藏物品”用例中,客户始终有两种选择:继续插入另一个贮藏物品或获得回收物品的收据。

  • 检查内部对象或属性的值或类型。例如,如果某个值大于或小于一个特定值,事件流就可能有所不同。

示例:

在自动柜员机系统的“取款”用例中,如果客户要求提取的金额大于他的帐户金额,事件流就会有所不同。因而,用例实例将遵循不同的路径。

用例实例的并行 返回页首

在系统允许的情况下,几个用例的实例和同一个用例的几个实例可以并行工作。在用例建模的过程中,您可以假定用例的实例可以毫无冲突地同时处于活动状态。由于用例建模不说明工作原理,所以应该用设计模型来解决这一问题。此时可以这样来看待这种情况,即假定一次只有一个用例实例处于活动状态,而且该实例的执行是一个不可分的活动。在用例建模中,“解释机”被认为是无限快的,所以用例实例的串行化不成问题。

名称 返回页首

每个用例都应有一个名称,以表明它与主角进行交互的结果。名称应该是几个便于理解的单词。用例名称不应重复。

示例:

回收机示例中的“回收贮藏物品”用例可以具有以下的不同名称:

  • 接收贮藏物品
  • 正在接收贮藏物品
  • 返回贮藏物品
  • 贮藏物品

简要说明 返回页首

用例的简要说明应反映用例的角色和目的。在撰写说明时,应参考用例中所涉及的主角、词汇表,并根据需要定义新概念。

示例:

以下是回收机系统中“回收贮藏物品”用例和“添加新的瓶类型”用例的简要说明示例:

回收贮藏物品:用户使用本机器来自动统计所有回收物品(瓶子、罐子以及箱子),并得到一张收据。收据将在收银机处兑现。

添加新的瓶类型:在“学习模式”中启动机器,然后与返回回收物品时一样插入 5 个样本,从而将瓶子的新类型添加到机器中。这样,回收机就能够测量这些瓶子,并知道如何识别它们。管理人员指定新的瓶类型的返款额。

事件流 - 内容 返回页首

用例事件流包含用例建模工作所得到的最重要的信息。应该清楚地说明用例的事件流,让外行也能很容易地理解它。请记住,事件流应该说明系统做什么,而不是说明为了执行所需的行为而对系统进行的设计。

以下提供了有关事件流内容的指南:

  • 说明用例如何开始和结束
  • 说明在主角和用例之间交换的是什么数据
  • 不要详细描述用户界面,除非要理解系统行为就必须详细了解用户界面。例如,如果事先知道应用程序将基于 Web,那么最好使用一组有限的 Web 专用术语。否则,您的读者就可能认为用例文本过于抽象。您可以在术语中包括这些词语:“导航”、“浏览”、“超链接”、“页”、“提交”和“浏览器”。不过,引用“框架”或“Web 页”时最好不要造成对两者之间界限进行臆测的效果。这是一项关键的设计决策。
  • 说明事件流,而不只是功能。为了做到这一点,每个动作都应从“当主角... 时”开始
  • 只说明属于该用例的事件,而不是发生在其他用例中或系统外部的事件
  • 避免不明确的术语,如“例如”、“等等”和“信息”
  • 详细说明事件流,即回答所有包含“什么”的问题。请记住,测试设计人员将使用此文本来确定测试用例。

如果您已经在其他用例中使用了某些特定术语,则务必要在此用例中使用完全相同的术语,并确保它们表达相同的含义。为了管理常用术语,应该将它们放入一个词汇表。

事件流 - 结构 返回页首

事件流的两个主要部分是基本事件流备选事件流。基本事件流应包括在执行用例时“通常”会发生的事件。备选事件流包括与正常行为相关的可选或异常特征的行为,同时也包括正常行为的各种变形。您可以将备选事件流看作是基本事件流的“绕行道”,有些备选事件流将返回到基本事件流,而有些将结束此用例的执行。

事件流的典型结构。直线箭头代表基本事件流,而曲线则代表与正常行为相关的备选事件流。有些备选路径返回到基本事件流,而其他备选路径则结束此用例。

应该将基本事件流和备选事件流进一步构建为步骤或分支流。为进行构建时,您的主要目标应该是文本的可读性(另请参见下面的事件流 - 风格一节)。这里的经验法则是,分支流应该是用例中的一个行为段,该行为段必须具有明确目的并且“不可分”(也就是说,要么执行所述的全部动作,要么不一个也不执行)。您可能会需要使用几个级别的分支流,但应尽量避免这样,因为多个级别的分支流会使文本更为复杂、更难于理解。可以用活动图来说明事件流的结构(参见指南:用例中的活动图)。

这种书面文本分为连续的小节,这本身就向读者提示:分支流之间存在一定顺序。为了避免误解,始终应该指出分支流的顺序是否是固定的。这种考虑事项通常与以下内容相关:

  • 业务规则。例如,在系统可以使某些数据可用之前,用户必须得到授权。
  • 用户界面设计。例如,系统不应强制行为的某个特定顺序,该序列对于某些用户可能是显而易见的,但对于其他用户却并非如此。

为了阐明备选事件流在结构中的合适位置,需要为基本事件流的每条“绕行道”说明以下内容:

  • 基本事件流中可以插入备选行为的位置。
  • 为使备选行为开始而需要满足的条件。
  • 基本事件流重新开始的方式和位置,或者用例结束的方式。

示例:

在回收机系统的“回收贮藏物品”用例中有一个备选分支流。

2.1. 瓶子阻塞

在 1.5 节“插入贮藏物品”中,如果一个瓶子被卡在入口处,入口周围的传感器和测量门将检测到这个问题。传送带停止传送,机器发出警报,让操作人员来解决问题。回收机将一直等待,直到操作人员指示问题已得到解决。然后,回收机从基本事件流的 1.9 节中继续工作。

在上例中,备选事件流插入了基本事件流中的一个特定位置。有些备选事件流也可以在多个位置插入,一些备选事件流甚至可以在基本事件流中的任意位置插入。

示例:

在回收机系统的“回收贮藏物品”用例中有一个备选分支流。

2.2. 前面板被取走

如果有人将回收机的前面板取走,将使罐子压缩功能不可用。没有前面板就无法启动罐子压缩操作。取走前面板的同时将激活向操作人员发出的警报。当重新安装好前面板时,回收机又将从它在基本事件流中停止的位置恢复操作。

如果备选事件流非常简单,您可能想就在基本事件流部分对其进行说明(使用某种不正式的“if-then-else"结构)。但应该避免这样。太多的备选事件流将使正常行为难于识别。而且,如果在基本事件流部分包括备选路径,将使文本更加“类似于伪代码”,从而会降低文本的可读性。

通常,如果抽取事件流的各个部分并且分别对这些部分进行说明,就可以增加基本事件流的可读性,并改进用例和用例模型的结构。您可以将抽取的部分建模为:

  • 基本用例中的一个备选事件流(如果抽取的部分是一个简单变量、选项或基本事件流的例外情况)。
  • 基本用例中的明确包含项(请参见指南:包含关系)(如果您希望将抽取的部分封装,以便其他用例复用)。
  • 基本用例中的隐含包含项(请参见指南:扩展关系)(如果基本用例具有完整的基本事件流,即具有确定的开始和结尾)。使用扩展流的情况应该是:您希望将其隐藏在基本用例的说明中,以降低该说明的复杂性。
  • 基本事件流中的分支流,并可能作为另一个选项(如果以上方案都不适用)。例如,在“维护雇员信息”用例中,可能有单独的分支流分别用于添加、删除和修改雇员信息。

事件流 - 风格 返回页首

可以按照多种风格来说明用例。作为示例,我们将以三种不同的风格来说明“管理订单”用例的基本事件流,它们的主要区别在于正式程度不同。第一种风格(如下面的示例 1 所示)易于理解、条理清晰,所以是推荐使用的风格。文本分为带有编号和名称的各个小节。这些编号便于对小节进行引用。小节名称使读者只需浏览文本的标题就可迅速地获得对从事件流的总体了解。

在下面的示例 2 中,事件流的说明没有阐明事件发生的顺序。如果以这种风格撰写,您和其他人都可能会错过一些与系统相关的重要信息。

下面的示例 3 显示了另外一种风格。如果您觉得很难清楚地表示事件的序列,就可以采用这种风格。这种伪代码风格更为准确,但非技术人员在阅读和理解这种文本时会有困难,尤其是在需要快速领会事件流时。

示例 1:
1.1. 用例开始

当主角操作员通知系统创建一个评测订单时,用例开始。然后,系统将检索所有的网络元素主角、它们的测评对象以及特定操作员可以使用的相应测评功能。可用的网络元素是那些正在运行的网络元素和操作员有权访问的网络元素。测评功能的可用性依赖于为某一特定类型的测评对象所设置的评测功能。

1.2. 配置测评订单

系统让操作员主角选择要评测的网络元素,然后将显示所选网络元素可以使用的测评对象。系统让操作员从这些评测对象中进行选择,然后选择需要为每个评测对象设置的评测功能。

系统让操作员输入对评测订单的文本注释。

操作员通知系统完成评测订单。系统将作出以下响应:为该评测订单生成一个唯一的名称,并设置评测开始时间、评测重复频率和评测持续时间的默认值。对于每个操作员,这些默认值都是唯一的。然后,系统让操作员编辑这些默认值。

1.3. 初始化订单

操作员通知系统初始化评测订单。系统将记录创建操作员的身份、创建日期以及测评订单的“预定”状态。

1.4. 用例结束

系统向该操作员确认已对测评订单进行了初始化,其他主角在此时可以看到该测评订单。

用例说明:在这种风格中,文本易于阅读,事件流易于理解。在您的说明中应尽量采用这种风格。

示例 2:
为了从网络元素中收集评测数据,订货人可以创建订单。

系统将给该订单分配一个唯一的名称,并指定评测持续时间和评测开始时间和评测重复频率的默认值。订货人将能够编辑这些默认值。

订货人必须进一步指定适用的评测功能、网络元素和评测对象。订货人还可以在订单上添加个人注释。

定义了必要的信息之后,将创建一个新的订单并使用已定义的属性、创建者姓名和创建日期来将这一新订单初始化。该订单的状态将被设置为“预定”。(可能的状态值包括:预定、执行、完成、取消和错误。)

然后,用户界面将得到已创建新订单的通知,同时会接收到对该新订单的引用,该引用可用来显示新订单。

用例说明:这种风格具有可读性,但事件流都不清晰。

示例 3:
'管理订单' (用户身份)
            REPEAT
            <='显示管理订单菜单'
            IF (=> '创建订单' (评测功能,
            网络元素,评测对象)) THEN
            系统查找唯一的名称、评测开始时间
            和持续时间的默认值。
            <= '显示订单' (默认属性)
            REPEAT
            => '编辑订单' (要更改的属性,属性的新值)
            <= '屏幕刷新' (新属性)
            UNTIL (定义了所有的属性)
            REPEAT
            IF (=> '编辑订单' (要更改的属性,属性的新值))
            THEN <= '屏幕刷新' (新属性)
            ELSIF (=> '保存订单' (订单标识,属性)) THEN
            在系统中创建订单,并使用已定义的属性、
            创建者的姓名、创建日期和“预定”状态
            将订单初始化。
            <= '创建的新订单' (订单)
            ENDIF
            UNTIL (=> '退出')
            ENDIF
            UNTIL '退出管理订单'

用例说明:编写员在上例中选择了一种使用伪代码的正式风格。这种风格会使读者难于快速领会流程步骤,但在不容易准确获取事件流的情况下,这种风格相当有用。

事件流 - 示例 返回页首

“管理订单”用例事件流的完整说明(包括其备选流)可能如下所示:

1. 基本事件流

1.1. 用例开始

当主角操作员通知系统创建一个评测订单时,用例开始。然后,系统将检索所有的网络元素主角、它们的测评对象以及特定操作员可以使用的相应测评功能。可用的网络元素是那些正在运行的网络元素和操作员有权访问的网络元素。测评功能的可用性依赖于为某一特定类型的测评对象所设置的评测功能。

1.2. 配置测评订单

系统让操作员主角选择要评测的网络元素,然后将显示所选网络元素可以使用的测评对象。系统让操作员从这些测评对象中进行选择,然后选择需要为每个测评对象设置的测评功能。

系统让操作员输入对评测订单的文本注释。

操作员通知系统完成评测订单。系统将作出以下响应:为该评测订单生成一个唯一的名称,并设置评测开始时间、评测重复频率和评测持续时间的默认值。对于每个操作员,这些默认值都是唯一的。然后,系统让操作员编辑这些默认值。

1.3. 初始化订单

操作员通知系统初始化评测订单。系统将记录创建操作员的身份、创建日期以及测评订单的“预定”状态。

1.4. 用例结束

系统向该操作员确认已对测评订单进行了初始化,其他主角在此时可以看到该测评订单。

2. 备选事件流

2.1. 没有可用的网络元素

在“1.1. 用例开始”中,如果发现目前没有该操作员可以评测的网络元素,系统将通知该操作员。该用例随即结束。

2.2. 没有可用的评测功能

在“1.2 配置评测订单”中,如果所选的网络元素没有可用的评测功能,系统将通知该操作员并让他选择其他网络元素。

2.3. 撤消评测订单

系统将允许操作员在用例执行过程中的任意时刻撤消所有动作。然后,系统将返回到该用例在开始之前所处的状态,并结束该用例。

特殊需求 返回页首

在用例的特殊需求中,应说明事件流没有包括的所有用例需求。有些非功能性需求将会影响设计模型。另请参见指南:用例模型中关于非功能性需求的讨论。您可以将这些需求分为不同的类别,例如可用性、可靠性、性能和可置换性,但是这些需求通常数量很少,所以这样的分类不具有太大的价值。

示例:

在回收机系统中,“返回贮藏物品”用例的特殊需求可以包括:

该机器识别贮藏物品的可靠性必须高于 95%。

前置条件和后置条件 返回页首

利用前置条件后置条件的概念来阐明事件流如何开始和结束是一种非常有用的方法。然而,只有当用例的读者认为该方法可以增加价值时才应将其采用。

前置条件是开始用例前所必需的系统及其环境的状态。后置条件是用例结束后系统可能具备的状态。

请考虑以下方面:

  • 前置条件或后置条件所说明的状态应该是用户可以观察到的状态。“用户已经登录系统”或“用户已经打开文档”都是可观察状态的示例。
  • 前置条件是对用例何时开始的约束。它并不是使用例开始的事件。
  • 虽然可以在分支流级别定义前置条件和后置条件,但是一个用例的前置条件并不只是一个分支流的前置条件。
  • 无论执行了哪些备选流,用例的后置条件都应为“真”;它只应对主事件流不为“真”。如果可能出现故障,则应在后置条件内包括“该动作已经完成,或者,如果可能出现故障,则不执行该动作”,而不只是“该动作已经完成”。
  • 当同时使用后置条件和扩展关系时,应确保扩展用例不引入违反基本用例后置条件的分支流。
  • 后置条件是一种对用例进行说明的有力工具。您可以首先定义用例应该实现什么,即后置条件。然后,可以说明如何达到这一条件(所需的事件流)。

示例:

自动柜员机中“提取现金”用例的前置条件为:客户拥有一张个人专用卡,这张卡正好可以塞进读卡器,并且该卡已经分到一个 PIN 号,还向银行业务系统进行了登记。

自动柜员机中“提取现金”用例的后置条件为:当用例结束时,所有帐户和交易日志都已收支平衡,与银行业务系统的通信已重新初始化,并且银行卡已经返还给客户。

扩展点 返回页首

扩展点使用例具有了扩展的可能性。一个扩展点有一个名称和一系列对用例事件流中一个或多个位置的引用。一个扩展点可以引用用例内的两个行为步骤之间的单个位置。它也可以引用一组不连续的位置。

使用已命名的扩展点将有助于将扩展用例的行为规约从基本用例的内部细节中分离出来。您可以对基本用例进行修改或重新整理,只要扩展点的名称保持不变,那么这种变更将不会影响扩展用例。同时,您不用在说明基本用例事件流的文本中包括有关行为可能在何处扩展的细节。请参见指南:扩展关系

示例:

在电话系统中,可以由抽象用例“显示呼叫方身份”来扩展用例“打电话”。这是一项可选服务,通常称为“呼叫方 ID”,接收方可能已请求该服务,也可能还未请求。用例“打电话”中扩展点的说明可能如下所示:

名称:显示身份

位置:在“1.9 节:使接收方的电话振铃”之后。

用例图 返回页首

您可能会选择在一个用例图(在很少的情况下会需要多个用例图)中阐明一个用例(用例图属于该用例)与主角以及其他用例的关系。如果用例涉及到许多主角,或者与很多其他用例有关系,那么用例图将非常有用。由于这种图只是从一个用例的角度来显示用例模型,而不用于解释整个用例模型的一般事实,所以它具有“局部”特征。另请参见指南:用例图


Email:campolake@gmail.com