介绍
测试设计是测试过程中最重要的部分之一。一个好的测试用例不仅要为被测系统( SUT )提供一些输入,还要验证系统是否如预期进行。也就是说,它有助于确认利益相关者要求得以实现。但测试设计可以做的远不止这些。理想情况下,测试设计有助于沟通两方对这些需求的理解,验证他们能被正确实施,并引发对利益相关者可能增加的更大价值的讨论。
基于模型的测试(MBT)(下文都简称为:基模测试)是一种技术,有时被标榜为“自动化测试设计”。虽然一定程度上这并没有错,但它或许会给人以错误的印象。基模测试工具从一个由用户指定的测试模型生成测试用例。没有测试模型,该工具就无法生成任何测试用例。没有好的测试模型,该工具就无法生成好的测试用例。因此,基模测试里,任务从测试设计变成了测试模型设计。不是设计单个测试集,我们设计了一个用于生成任何数量的测试用例的测试模型。
例子
为了给这个概念提供一个具体的理解,首先我们举一个简单的例子。这里所说的例子使用OSMO Tester MBT生成器的符号,它基于Java编程语言。这种情况下,测试模型是使用标准的Java编程语言结构编写的,但却被设计成被另一个称作测试生成器的程序以不同的方式执行,以生成测试用例。有时候,这种模型被称为模型程序。
图1举了一个简化电信系统(其中多个移动终端被连接(注册)到潜在多个服务器之一上,彼此相互调用)的这种符号的例子。
其他类似工具用于各种其他平台,比如Python (PyModel)和.NET (Spec Explorer, NModel)。其他基于Java的工具和符号,包括ModelJUnit和Conformiq Designer。许多工具也定义了自己的建模语言,并提供一种方法将模型以不同的方式进行可视化。
根据用户的喜好,可以选择不同的工具提供一个熟悉的工作环境以及不同的算法和不同的特征等。
[BINDER]中可找到一个MBT工具列表。
注意,图1中的试验模型被稍微简化以提供一个测试模型中的一些核心要素的例子。测试这样一个系统的真实模型将包含更多步骤,动作和检查,以及更多的规定。例如,我们需要来启动和终止调动的步骤,注销终端步骤,移动它们的网络的步骤,启动数据传输不同类型的步骤,等等更多。
至于这种模型中的规定,我们应该保持终端列能有效调用,消息列可以发送和接收,并保证一切有效数据传输。并且应在测试先知中用类似于图1中检查注册终端的方式去再次坚持这项新规定。本文的其余部分将把示例模型引用为一个扩展版本。一个测试生成器可采取不同的方法从一个测试模型生成测试用例。对于OSMO Tester生成器及图1所示测试模型,该模型可能如[ ACM ]所述那样被最直观地描述为一系列规则和动作。该模型定义了一组可以在被测系统上进行的动作(在OSMO Tester标记中用作@TestStep的一部分)。当这些动作中的每一个都被允许时,一组规则(OSMO Tester标记中的@Guard)就定义了。规则允许的话,生成器就以不同的方式组合这些动作以生成测试用例。整个测试模型可以被视作用来描述大量的可能测试用例集。随后测试生成器从(使用一些由用户定义的覆盖准则的)这个模型去生成测试用例。可用标准的变化取决于所使用的工具,但一些例子包含了在模型中覆盖用户指定要求(手动标记的特定部分或路径),覆盖动作组合,并覆盖不同动作的各种数据值。(可能已被用来为我们的示例模型指导生成器的)覆盖准则的一些例子包括:注册终端的数量,调用终端的数量,注册却自由(不处于调用状态)的终端的数量,及动作结果配对。例如,它可以被定义为对将“零”,“一”和“多”类别都覆盖到终端类型数中的每一个很感兴趣。动作覆盖可以与这些数值中的一些进一步配对,以激励生成器来生成步骤,诸如注销一个调用终端和注销一个不同配置下的非调用终端。有了更严格/松散的覆盖目标,以及从自由度变为在测试用例中添加随机性,那么生成机就可以被用来生成一组更小/更大的测试用例。
图2是一个(含有图1模型中的一个测试生成流程的四个不同点的)例子。在点一( 1 )中 ,模型程序被5个未注册终端初始化了。在点二(2 )中,生成由几个步骤推进,且三个终端已被注册。在点三( 3 )中 ,几个步骤再次被通过且两个注册终端有了有效调用(两者间的单独调用)。在点四( 4 )中,两个以前未注册的终端已经被注册了,前面调用的一部分已经退出,已用两个终端建了一个新的调用。
它真正测试哪些东西呢?
测试生成的一个常见问题是:它真正测试什么呢?如果我们只是无休止地生成测试数据或测试步骤却对结果的正确性一无所知,那还有什么意义呢?在基模测试中,测试模型也可以用来检查测试用例。图1中这是由模型中@Post注释的方法举例说明的。生成器在所有的测试步骤两两间(后)执行这个过程,以证明被测系统的情况与测试模型的情况一致。例如,在图2的点二( 2 )中,它会检查是否测试模型中被标记为注册的三个终端在被测系统中也都处于相同情况。它还要检查其他两个没有被注册,而且他们都没有正在进行有效调用。
类似地,更具体的检查可以嵌入到任何可在其中获得一些具体结果的行动中去。
如果需要的话,这些检查可以是不同粒度的,且可以在按量进行,因为不像手工脚本,他们不需要手工编写每个测试用例的每一步,却可以由测试生成器进行,时间间隔与时间长短都不限。
当已经创建了一个测试模型,测试生成器就用来从这些模型生成测试用例。除了用指定的覆盖准则为指导从整体模型生成测试,很多MBT工具还提供了一种手段来指导生成器用各种形式的用户定义场景去关注特定部分。例如,有了(有调用等的)扩展示例模型,我们或许还想从某个角度专注分析管理终端注册的网络服务器。要做到这一点,用户可以创建一个场景,确保只有测试步骤与该场景(如注册和注销)相关联。
工具的具体场景定义语言,可以用来建立这样的场景。要建一个特定测试配置,测试模式可用指定终端实例被参数化。
图3说明了为我们只允许注册和注销步骤的示例模型建立一个场景,且每个步骤都必须在每个生成的测试用例中出现至少两次。
更真实的例子会包括更多步骤,更多部分,并且可能还包括用以驱动SUT到场景起点的启动脚本。
这样一个场景甚至可以用来定义一个特定动作序列,该序列将被用作一个启动脚本以生成一个类似于手工编写测试用例的纯手工特定测试用例,而不是当模型和其他生成的测试用例一样变化时将被更新。
测试设计是测试过程中最重要的部分之一。一个好的测试用例不仅要为被测系统( SUT )提供一些输入,还要验证系统是否如预期进行。也就是说,它有助于确认利益相关者要求得以实现。但测试设计可以做的远不止这些。理想情况下,测试设计有助于沟通两方对这些需求的理解,验证他们能被正确实施,并引发对利益相关者可能增加的更大价值的讨论。
基于模型的测试(MBT)(下文都简称为:基模测试)是一种技术,有时被标榜为“自动化测试设计”。虽然一定程度上这并没有错,但它或许会给人以错误的印象。基模测试工具从一个由用户指定的测试模型生成测试用例。没有测试模型,该工具就无法生成任何测试用例。没有好的测试模型,该工具就无法生成好的测试用例。因此,基模测试里,任务从测试设计变成了测试模型设计。不是设计单个测试集,我们设计了一个用于生成任何数量的测试用例的测试模型。
例子
为了给这个概念提供一个具体的理解,首先我们举一个简单的例子。这里所说的例子使用OSMO Tester MBT生成器的符号,它基于Java编程语言。这种情况下,测试模型是使用标准的Java编程语言结构编写的,但却被设计成被另一个称作测试生成器的程序以不同的方式执行,以生成测试用例。有时候,这种模型被称为模型程序。
图1举了一个简化电信系统(其中多个移动终端被连接(注册)到潜在多个服务器之一上,彼此相互调用)的这种符号的例子。
其他类似工具用于各种其他平台,比如Python (PyModel)和.NET (Spec Explorer, NModel)。其他基于Java的工具和符号,包括ModelJUnit和Conformiq Designer。许多工具也定义了自己的建模语言,并提供一种方法将模型以不同的方式进行可视化。
根据用户的喜好,可以选择不同的工具提供一个熟悉的工作环境以及不同的算法和不同的特征等。
[BINDER]中可找到一个MBT工具列表。
图1.模型程序示例
注意,图1中的试验模型被稍微简化以提供一个测试模型中的一些核心要素的例子。测试这样一个系统的真实模型将包含更多步骤,动作和检查,以及更多的规定。例如,我们需要来启动和终止调动的步骤,注销终端步骤,移动它们的网络的步骤,启动数据传输不同类型的步骤,等等更多。
至于这种模型中的规定,我们应该保持终端列能有效调用,消息列可以发送和接收,并保证一切有效数据传输。并且应在测试先知中用类似于图1中检查注册终端的方式去再次坚持这项新规定。本文的其余部分将把示例模型引用为一个扩展版本。一个测试生成器可采取不同的方法从一个测试模型生成测试用例。对于OSMO Tester生成器及图1所示测试模型,该模型可能如[ ACM ]所述那样被最直观地描述为一系列规则和动作。该模型定义了一组可以在被测系统上进行的动作(在OSMO Tester标记中用作@TestStep的一部分)。当这些动作中的每一个都被允许时,一组规则(OSMO Tester标记中的@Guard)就定义了。规则允许的话,生成器就以不同的方式组合这些动作以生成测试用例。整个测试模型可以被视作用来描述大量的可能测试用例集。随后测试生成器从(使用一些由用户定义的覆盖准则的)这个模型去生成测试用例。可用标准的变化取决于所使用的工具,但一些例子包含了在模型中覆盖用户指定要求(手动标记的特定部分或路径),覆盖动作组合,并覆盖不同动作的各种数据值。(可能已被用来为我们的示例模型指导生成器的)覆盖准则的一些例子包括:注册终端的数量,调用终端的数量,注册却自由(不处于调用状态)的终端的数量,及动作结果配对。例如,它可以被定义为对将“零”,“一”和“多”类别都覆盖到终端类型数中的每一个很感兴趣。动作覆盖可以与这些数值中的一些进一步配对,以激励生成器来生成步骤,诸如注销一个调用终端和注销一个不同配置下的非调用终端。有了更严格/松散的覆盖目标,以及从自由度变为在测试用例中添加随机性,那么生成机就可以被用来生成一组更小/更大的测试用例。
图2是一个(含有图1模型中的一个测试生成流程的四个不同点的)例子。在点一( 1 )中 ,模型程序被5个未注册终端初始化了。在点二(2 )中,生成由几个步骤推进,且三个终端已被注册。在点三( 3 )中 ,几个步骤再次被通过且两个注册终端有了有效调用(两者间的单独调用)。在点四( 4 )中,两个以前未注册的终端已经被注册了,前面调用的一部分已经退出,已用两个终端建了一个新的调用。
图2.测试生成流程示例
它真正测试哪些东西呢?
测试生成的一个常见问题是:它真正测试什么呢?如果我们只是无休止地生成测试数据或测试步骤却对结果的正确性一无所知,那还有什么意义呢?在基模测试中,测试模型也可以用来检查测试用例。图1中这是由模型中@Post注释的方法举例说明的。生成器在所有的测试步骤两两间(后)执行这个过程,以证明被测系统的情况与测试模型的情况一致。例如,在图2的点二( 2 )中,它会检查是否测试模型中被标记为注册的三个终端在被测系统中也都处于相同情况。它还要检查其他两个没有被注册,而且他们都没有正在进行有效调用。
类似地,更具体的检查可以嵌入到任何可在其中获得一些具体结果的行动中去。
如果需要的话,这些检查可以是不同粒度的,且可以在按量进行,因为不像手工脚本,他们不需要手工编写每个测试用例的每一步,却可以由测试生成器进行,时间间隔与时间长短都不限。
当已经创建了一个测试模型,测试生成器就用来从这些模型生成测试用例。除了用指定的覆盖准则为指导从整体模型生成测试,很多MBT工具还提供了一种手段来指导生成器用各种形式的用户定义场景去关注特定部分。例如,有了(有调用等的)扩展示例模型,我们或许还想从某个角度专注分析管理终端注册的网络服务器。要做到这一点,用户可以创建一个场景,确保只有测试步骤与该场景(如注册和注销)相关联。
工具的具体场景定义语言,可以用来建立这样的场景。要建一个特定测试配置,测试模式可用指定终端实例被参数化。
图3说明了为我们只允许注册和注销步骤的示例模型建立一个场景,且每个步骤都必须在每个生成的测试用例中出现至少两次。
更真实的例子会包括更多步骤,更多部分,并且可能还包括用以驱动SUT到场景起点的启动脚本。
这样一个场景甚至可以用来定义一个特定动作序列,该序列将被用作一个启动脚本以生成一个类似于手工编写测试用例的纯手工特定测试用例,而不是当模型和其他生成的测试用例一样变化时将被更新。
MBT的优点 基模测试的优点很多。相对于手动设计(编写)单个测试用例,建立测试模型意味着有必要考虑和确定被测系统的整体行为。根据我们的经验,反之这促使了组织间的交流以便把要求建立这样一个模型的各方都汇集起来,既有利于协作又促进共同理解。 当从一个单一的模型生成大量测试用例时,维护也被简化了,而且更新模型一次并重新运行生成器会可以立刻更新所有测试用例,而不要单独重新运行几百个测试用例。 一个精心设计的测试模型表现出了作为一个整体的被测系统的被选方面。被允许和支持的测试值而不是单个测试值的范围应该在测试模型中被发现并表示。不利用测试(模型)设计师把开发人员和领域专家聚到一起是不可能。也许基模测试应用中通常观察到的最大的好处是:建设和共享对系统的限制和功能的明确理解,并把所有的假设都列到表格中。 当这种理解被记录到一个测试模型中,某种程度上它就成了一个可执行的规范,因为它可以被用来生成测试用例以实施。然后,不断的测试用例将验证被记录的理解也与实施一致。如果不是这样,就有待达成一个新的共同的理解,细化的模型,或不变的实施。 当然,该测试模型不能充分地描述该被测系统的所有可能的行为,或者它会变得和实现本身一样复杂甚至更复杂。因此,需要为建模内容选择一个合适的范围,为测试模型选择一个相当高的抽象级别。测试模型的设计需要把重点放在系统的核心部分,该核心部分被视为对严格的测试和验证最重要。这个变化要跨几个系统,例如,安全关键系统可能比不太重要的应用包含了更详细的内容。因为基模测试过程不仅提供了所生成的测试用例,而且还有对系统规范和功能的严格审查,这个审查被要求用来生成测试模型。我们发现这对一个高层次的系统概述和核心关键要素的详细研究特别有用。 从测试生成的角度来看,基模测试的主要好处在于它的自动模型探索能力且在探索测试模型中不挑测试生成器。根据我们的经验,一个领域(测试)专家要查看系统并对它是如何工作的做出某些内在假设很简单,凸显一些东西,在手动设计测试用例中重复这些假设。手工操作也很昂贵,在各种不同的开发迭代中很少有时间或资源来广泛测试一大组不同的选项,或者保证一个大堆测试得以审查和更新。 使用测试模型为基础的测试生成器的限制较少。有一个好的测试模型,该工具就可以结合不同的模型覆盖准则探索不同场景并把随机模型覆盖融合进去,就避免了一些专业偏差还扩大了探索选项集合。自然,该工具无法避免模型内的偏差,但是当几位专家一起进行模型工作(甚至部分,如审查)时,模型具有巨大偏差的可能性就小了,工具将更加不知疲倦更彻底地探索模型。在现有计算能力和测试执行时间内,它可以生成并执行大量测试用例而不会厌倦,并在每次迭代中重复同样的过程,只需更新单个测试模型就行。 许多关于使用基模测试的案例研究已经发表,也许这其中最广泛的就是微软协议文档工作[ ACM ] 。微软研究表明:把所有元素(包括学习曲线等)考虑在内时使用基模测试对比手工脚本有42%的利益。它还强调了许多我们所观察到的接下来将要讨论的问题。 采用需求及潜在问题 如果基模测试这么棒,为什么我们不一直用它呢?因为基模测试的初始成本较高,需要多样化的技能,它的利益却难以衡量。初始成本用于获取技能,学习测试建模的思维模式,并创建测试模型。无法证明自己的系统和域的好处的话,这样的初始成本很难被接受,如果所有人至今为止都一直手写测试,就很容易安于现状而不会为组织去尝试不同的和未知的事物。 创建良好的测试模型需要良好的编程技巧(及一般的软件工程技能),测试专业知识,建模专业知识和领域专业知识。这是一个多样化的技能组合,很难靠单个专家获得。而当有这样的专家时,管理层往往快速将他们分配定位成为一个开发而不是测试。同样,管理层基本不会提供各种昂贵的资源(如领域专家,软件开发人员)用于和软件测试的筒仓相关的活动,即使他们需要成功的测试活动。从模型设计角度来看,测试模型也并不是一个传统的顺序计算机程序,而是指导测试生成器的一个规则和行动的集合,它本身与传统的顺序程序设计有点不同。 一般情况下,当开始进行评估,(可能的话)采用基模测试方法的时候,或许最大的障碍就是需要采用一个完全不同类型的思维模式。有必要把重点放在考虑SUT的整体功能和目的或者它所选择的一部分上,而不要独自想着单用场景和单个测试用例。这需要与组织中的其他专家密切合作,这就可能需要对一般的工作实践稍作改变。 这也强调了关于计算优点的问题。如果管理被用来测量如被写测试用例的数量之类的东西,他们要么就看不到测试用例(只有一个测试模型)要么就是一大堆测试用例(所有生成的)。 [ GRAHAM ]中已对该问题及其可能结果做了详细说明,[ GRAHAM ]中测试人员最初恶评如潮,后来因为已观察到的影响而被承认。还有,最初获得用该工具生成测试用例的启动成本会显得使用这种规格没有任何价值。然而,它可以是建立共同理解并将之记录在一个可执行的规范(测试模型)中的过程中最有用的部分。正如在任何自动化测试工作(或任何其他工作)中 ,管理支持,沟通和理解都是非常重要的。 该方法和测试生成结果的有效性取决于设计的测试模型的质量。没有一个高质量的模型,就没有测试生成可以生产好测试。因此,投入足够精力去产生好模型并和其他专家一起检验它很重要。 生成一大组测试用例也能生出一大组需要进行分析的结果。根据我们的经验,当考虑实施基模测试时,许多人通常认为这就是一个潜在的问题。然而,实践中,我们已经观察到:这问题不大,因为测试生成基本是使用某种形式的场景或(对系统具体部分分析关注的)专注模式指导的。然而,模型设计仍应仔细考虑诸如有趣元素有哪些以及它们从所有可能输入到测试的组合,所以测试生成的重点应放在最有用的方面。至于结果分析,积极地说,当更多的精力可以从手动复制测试脚本中被转移到分析结果时,这就可以使工作更有趣而不那么单调乏味。总之,测试自动化应该一层层往上建。 有效实施基模测试需要将之建于一个好的基础的测试自动化平台之上。如果它无法写出可以自动化执行的测试脚本,那么继续进行基模测试去产生这样的脚本就毫无意义。建立基础的测试自动化需要良好的水平,这个水平上,基模测试过程可作为一个额外工具来提高总体质量。例如,如自动控制SUT的GUI进行测试一类的事,应该在测试一个基于GUI的应用程序时就得到解决。 过程 使用基模测试的过程可以用四个简单的步骤描述为一个迭代过程,图3所示。开始时,我们通常为系统所选的小一部分创建一个最初的测试模型。这使我们能够学习基本工具和框架,并看看他们是如何连接以形成整个测试环境并在该环境中定位基模测试工具。
图4.过程模型设计 一旦拥有了测试模型的工作版本,我们就用它来生成并执行测试用例。生成的测试用例的执行可以在所谓的“在线基模测试”中与他们的生成进行交错,或在所谓的“离线基模测试”中的一个单独的阶段中完成。这就很快地给我们提供了对模型情况和对当前模型设计中被测系统的那些部分的反馈。 当我们已经生成并执行测试用例时,我们分析出被测系统上及测试模型中错误的结果。 在令人满意的水平上,我们开始一步步地扩展模型并添加更多功能。这意味着我们要从头重复这些步骤及这个过程,直到在我们觉得我们已得到了一个描述有趣元素的合适水平上的测试模型。 一些测试模型可以用来设计系统的不同部分。测试场景被用来指导测试生成,或者它可以使用不同的模型和生成器配置去重点关注不同的区域和观点。 我们采用的一种做法是帮助合作伙伴开始使用开源工具理解这个概念,看到好处,并学习技术。开源工具也有适应特定需求和环境的优点。一旦基本技术,及其实施和效益被更好的理解了,就可以选取不同的前进道路,包括转用(从广泛付费支持和大规模开发先进算法的资源获益的,如Spec Explorer和Conformiq Designer的)商业工具这个选择。然而,在许多情况下,我们早已经看到了开源选项提供的不错利益。 可以运用基模测试的一个好地方是有很多变量和很多(需要进行测试的)交互的地方。一旦我们意识到把这个手动缩放到要求的复杂度和质量水平很昂贵的时候,基模测试就是一个值得考虑的好技术。另一个不错的地方是安全性软件,在这种软件中必须完全相信一个好的几乎无错的解决方案已被建成。 结论 基模测试可能听起来像一个很酷但却吓人的技术,很难上手。然而,经过一些初步学习之后,它并不比常规测试和测试自动化更复杂。我们一般采取的做法是建议一开始(最好是在熟悉这个概念的人的帮助下让对该方法及其潜力超振奋的人)把它用在一个较小的试点项目中。我们通常以现有的测试自动化和测试脚本为出发点,以这些为基础一次一小部分地开始建立测试模型。至于抽象层,一个好的起点可以是:(通过利用现有的SUT的API去定义可能采取的行动或关注可以观察到很多变化且很难测量手动测试的地方,在该系统复杂/易出故障的部分或在核心关键功能上,构建一个促进共同理解的高层次的总体模型中的)任何东西。 作者介绍: TeemuKanstrén是一名资深科学家,目前在芬兰VTT技术研究中心工作,他还是多伦多大学的一名客座博士后。他的工作涉及:以改进行业现状,和生产实际有用的解决方案并帮助行业伙伴接受采纳它们为目的的自动化测试领域的研究和开发。他软件行业工作了好几年,已帮助众多合作伙伴开发和采用以基于模型的测试技术为基础的测试自动化解决方案。他是开源的基于模型的测试工具OSMO Tester的主要创造者。2010年他获得了芬兰大学测试自动化和基于模型的测试的博士学位。 |
最新内容请见作者的GitHub页:http://qaseven.github.io/