状态转换图
状态转换图是对特定系统需求设计测试用例的工具之一,它描述了测试对象和测试数据之间的关系。测试对象的输出和行为方式不仅和当前的输入数据有关,而且与测试对象当前的状态有关。状态转换图是设计状态转换测试用例的基础,基于状态转换图进行的测试就是状态转换测试。
测试对象从初始状态可以转换到不同的状态,状态转换图中的各个状态通过不同的事件驱动,如函数调用;除了初始状态之外,还有一个特殊的状态是结束状态。下面通过具体的例子说明状态转换测试。
某航空公司的订票系统
某航空公司订票系统的状态描述如下。
(1)客户提供机票信息(该事件表示为GiveInfo),如离开城市、到达城市、航班日期和时间等。订票系统将根据这些信息订票,此时订单状态为Made。
(2)在客户提供机票信息的同时订票系统启动一个计时器(该事件表示为StartPayTimer),要求客户在指定时间内必须付费。
(3)在计时器超时之前客户付费(该事件表示为PayMoney),那么状态转换为Paid。
(4)处于Paid状态的客户打印机票(该事件表示为Print),订票系统将为客户出票(该活动表示为Ticket),那么状态转换为Ticketed。
(5)客户使用机票登机(该事件表示为GiveTicket)之后,状态转换为Used,并且整个状态转换结束。
(6)如果在计时器超时之后客户还没有付费,订票系统将取消本次机票预订(该事件表示为Cancel),那么状态转换为CancelledNonPay。
(7)如果在计时器超时之前客户要求取消本次订票,则状态转换为CancelledByCustomer。
(8)如果客户在付费之后取消订票,则状态转换为CancelledByCustomer,但是需要将相关的机票款项退还给客户(该事件表示为Refund)。
(9)如果客户在拿到机票之后取消订票,状态也转换为CancelledByCustomer。客户需要将机票退回航空公司(该条件表示为ReturnTicket),航空公司在收到退票之后将机票费用返还给客户。
根据该订票系统规格说明,得到如下图所示的订票系统的状态转换图。
(1)状态:以圆圈表示,状态可以反映系统以前的事件,并决定系统对可能发生的事件的反应。
(2)转换:以箭头表示,转换指的是由于事件的驱动,系统从一个状态到另一个状态。
(3)事件:和特定的转换相关联,以具体的事件名称表示。事件可以驱动状态的转换或者其他动作,通常来说,事件由系统的相关接口触发,也可以来自系统内部,如计时器超时。事件可以是独立的,也可以是相互关联的,如事件A必须在事件B之后发生。
(4)活动:以“/”形式表示,活动由状态转换触发,如出票(Ticket)。通常情况下活动得到的结果会作为系统的输出。活动一般在状态转换过程中发生。
(5)条件:以“[]”表示,条件可以是True或False,说明状态转换只有在满足这个条件之后才能进行。
(6)特殊状态:开始状态和结束状态。
测试用例
有了状态转换图之后即可设计测试用例,从状态转换图直接得到测试用例有一定难度,尤其是在图中状态和转换比较复杂的情况下。状态转换测试经常利用状态转换树或状态转换表设计测试用例。
1.状态转换树
根据状态转换树设计测试用例,首先需要将状态转换图转换为状态转换树,即将可能具有无限多状态循环的状态转换图转换为不含循环的具有一定数目状态的状态转换树。转换过程需覆盖所有的状态,并且包含状态转换图中的所有转换。将状态转换图转换为状态转换树的基本步骤如下。
(1)将初始状态或开始状态作为状态转换树的根,根在整个状态转换树中的层次是1。
(2)假设当前生成状态转换树的层次为K,那么从左到右检查所有层次为K的节点。将该节点对应的所有下一个可能状态作为其子节点,状态之间的转换作为两个状态的边。
(3)重复(2),直到一个位于层次K上的节点出现在层次J上,且J≤K
。这个节点成为最终的叶节点,无须继续生成其子节点。或者节点的状态是结束状态,也不需要针对该节点继续进行状态转换。
根据状态转换图到状态转换树的转换规则,将前面订票系统的状态转换图转换为状态转换树。由于订票系统中没有循环结构,所以整个转换过程比较简单。生成的订票系统的状态转换树如下图所示。
生成订票系统的状态转换树后即可根据不同的测试强度(或者不同的测试覆盖率级别)得到如下测试用例列表。
(1)至少覆盖所有的状态一次:3个测试用例即可满足该覆盖率要求,如下图所示。
(2)至少覆盖所有的事件一次:3个测试用例就能够覆盖所有的事件。在本案例中覆盖所有事件和所有状态的测试用例相同,如图3-9所示。
(3)至少覆盖所有的状态转换一次:需要5个测试用例才能够覆盖所有的状态转换。这个级别的测试可以提供较好的测试覆盖率,也可以确保生成的测试用例数目不是很庞大。这是状态转换测试技术经常使用的覆盖率,如下图所示。
(4)至少覆盖所有的路径一次:这个级别的覆盖率最高,但经常是不现实的。如果状态转换图中有循环的情形,那么可能的路径是无穷的。例如,测试对象有两个状态A和B,并且之间是循环关系。即状态A可以到B,状态B可以到A。可能的路径如下:
A→B。
A→B→A。
A→B→A→B→A→B。
A→B→A→B→A→B→A。
A→B→A→B→A→B→A→B→A→B。
…
如果一直这样循环,那么得到的路径将是无穷的。但是覆盖这样循环的测试用例对于发现一些累计的计算错误或者资源方面的缺陷非常重要,如内存泄漏。所以在设计测试用例的过程中,需要确定合适的覆盖率。
除了设计测试用例覆盖所有的状态、事件和路径之外,还需要检查在不同状态情况下错误调用函数的测试用例(如在不同状态时调用不同的事件)。这是一个健壮性测试,验证测试对象在调用错误事件时,是否会出现错误的状态转换,类似无效数值的输入。健壮性测试可以根据实际的测试对象、测试成本和测试时间等方面的情况确定其测试范围。
2.状态转换表
状态转换表可以从状态转换图中得到,也可以直接通过测试对象的规格说明得到。它由4个部分组成,分别是当前的状态、事件、活动和后续状态。根据图3-6可以得到相应的状态转换表,如下表所示。
状态转换表的优点是罗列了所有可能的状态转换组合,而不仅仅是有效的状态转换。针对高风险的系统,如安全关键系统,测试每个状态转换组合是需要的;另外创建状态转换表可以发现测试对象规格说明中可能遗漏的组合,或者没有文档化的组合。如果在编码之前能发现这方面的缺陷,对提高产品质量和降低成本非常有益。
利用状态转换表可以发现测试对象实现方面的问题,如实现了无效或者不希望的状态转换路径(从一个状态到另一个状态的转换)。状态转换表的一个主要缺点是当测试对象的状态和事件增加时,它会快速地增加;另外状态转换表中的很多单元格是多余,甚至空白的。
从状态转换表中得到测试用例比较简单,直接读取即可。例如,表3-16所示的订票系统的状态转换表中,灰色的条目就是所有有效的状态转换(其中当前状态类似测试用例的前置条件,事件是输入,活动和后续状态是期望的结果),最终生成的有效状态转换的测试用例如下表所示。
选择有效的状态转换之后,可以根据测试对象的风险选择部分无效的状态转换,确定测试对象是否实现了某些不应该实现的无效状态转换。
N-Switch
N-Switch是由TSUN S. CHOW在1978年提出的,他将N-Switch定义为程序图中长度为n+1的连续的边或弧线(通常在状态图中表示循环)的序列。所以单独的一条边(或者转换)就是一个0-Switch,两条连续的边的序列就是1-Switch。
如图所示为状态机。
其中圆圈表示状态,带箭头的边表示转换;同时为每个转换定义了一个英文字母的标识。根据0-Switch的定义,该状态机对应的所有的0-Switch为a、b、c、d、e和f。根据3.4.2节中的0-Switch状态转换树生成规则,生成的0-Switch状态转换图如下图所示。
再来看1-Switch。根据1-Switch的定义,该状态机对应的所有1-Switch为ab、ac、bb、bc、cd、ce、dd、de、ea、ef、fd
和fe。1-Switch状态转换树的生成规则是在0-Switch状态转换树基础上再增加一个层次,即针对0-Switch状态转换树的所有叶节点,把每个叶节点可能的下一个状态作为该节点的子节点。需要注意的是只需要增加一个层次。生成后的1-Switch状态转换图如下图所示。
覆盖率准则
如测试用例节所述,状态转换测试有如下测试强度,即覆盖率准则。
- 状态覆盖:每个状态至少执行一次。
- 事件覆盖:每个事件至少执行一次。
- 状态转换覆盖:每个状态转换至少执行一次。
- 路径覆盖:每个路径至少执行一次。
测试过程中可以根据选择的覆盖率准则判断当前测试的充分性,对于要求高或者风险大的测试对象,如安全关键系统和综合系统,可能需要更加严格的状态转换测试覆盖率。但是更高的测试覆盖率往往会带来测试用例数目过于庞大的问题,因此具体的状态转换测试覆盖率的选择需要考虑风险、时间和成本等各个方面的因素。
酷客教程相关文章:
评论前必须登录!
注册