组织测试_测试组织

其他范文 时间:2020-02-27 10:41:01 收藏本文下载本文
【www.daodoc.com - 其他范文】

组织测试由刀豆文库小编整理,希望给你工作、学习、生活带来方便,猜你可能喜欢“测试组织”。

第12章

组 织 测 试

12.1 关于本章

包括第11章“使用测试替身”在内的几章,出于验证SUT行为的目的,介绍了与它交互的各种方法。本章将讨论如何组织测试码,以便于发现和理解它们。

测试码组织的基本单元是测试方法。决定在测试方法内放置什么以及将它放置在哪里是测试组织的中心主题。如果只有一小部分测试,如何组织它们不是特别重要。相反,如果有几百个测试,测试组织就变成了保证测试易于理解和发现的重要因素。

本章首先讨论应该在测试方法内包含什么,不应该包含什么。接下来将探讨如何决定用哪些测试用例类来设置测试方法。测试命名主要取决于组织测试的方法,因此随后可以讨论这个问题。然后考察将测试用例类组织到测试套件的方法以及放置测试码的位置。最后一个主题是测试码重用,特别是,将可重用的测试码放置在哪里的问题。

12.2 基本的xUnit机制

测试自动化架构的xUnit家族提供了许多特征来帮助组织测试。将测试码放置到测试用例类上的测试方法中,可以回答基本问题“在哪里编码测试?”。然后使用测试发现或测试枚举来创建测试套件对象,该对象包含所有来自测试用例类的测试。测试运行器调用测试套件对象上的方法来运行所有测试方法。

12.3 合理精简测试方法

测试条件是用来证明SUT确实运行的条件。它可以用下面的形式描述:SUT的起始状态是什么、如何执行SUT、希望SUT如何响应以及SUT的预期结果是什么。测试方 112 第Ⅰ部分

法是测试脚本语言中的一系列语句,它执行一个或多个测试条件,如图12-1所示。在单个测试方法中应该包含什么?

testMethod_1 建立 测试运行器 Run 创建 执行 执行 验证 拆卸 testMethod_n 创建 testMethod_n 执行 SUT 创建 Testcase Object 夹具

图12-1 典型测试的4个阶段。每种测试方法实现一个四阶段测试,该测试最理想的情况是验证

单个测试条件。不是所有四阶段测试都需要在测试方法中

许多xUnit纯化论者喜欢每个测试验证一种条件,因为这样可以提供好的缺陷定位。也就是说,测试失败时,他们能够确切知道SUT中什么出了问题,因为每个测试只验证一种测试条件。这与手动测试形成了鲜明对比,在手动测试中,考虑到建立每个测试前置条件所涉及的系统开销,人们总是构建长长的、包含多种条件的测试。创建基于xUnit自动化测试时,有许多方法可以解决这种经常重复的夹具建立问题(如第8章“暂时夹具管理”所述),因此倾向于每个测试验证一种条件。我们将验证多种测试条件的测试称为急切测试(Eager Test,参见“断言滚轮”),并将它作为代码味道。

验证单个测试条件的测试执行通过SUT的单个代码路径,它每次运行时都应该执行相同的路径,这就是它成为可重复测试的原因。的确,这意味着需要与通过代码的路径一样多的测试方法,但希望其他测试如何实现全代码覆盖呢?让这个模式变得易管理的是给每个类写单元测试时隔离SUT,因此只需要关注通过单个对象的路径。同时,因为每个测试应该只验证一个通过代码的路径,所以每个测试方法应该由严格连续语句组成,这些语句描述在那个路径上应该发生什么1。每个测试验证一种条件的另一个原因是要最小化测试重叠,这样如果后面要修改SUT的行为,就只需要修改少量测试。

Brian Marrick开发了一种有趣的折衷方法(我称之为“我们一直干个不停”2),它利用已经建立的测试夹具来运行其他一些核查和断言。Marrick用注释清楚地标记这些元素来说明,如果对SUT的变更废弃了测试的那个部分,就完全可以删除它们。这种策略将维护其他测试码所需的努力降到了最小。包含条件测试逻辑的测试方法是试图适应不同环境的测试的标记,因为它不能控制SUT的全部间接输入或者因为它要在测试方法内的内联基础上验证复杂的预期状态。他称之为“博取开心一笑”,但我不认为这个名称的意图很明显。

第12章

组 织 测 试

113

12.4 测试方法和测试用例类

测试方法需要依赖测试用例类而存在。应该将所有测试方法放置到应用程序的单个测试用例类上吗?还是应该为每个测试方法创建一个测试用例类?当然,正确的答案是将这两种极端折衷一下,它将完全改变项目的面貌。

12.4.1 每个类一个测试用例类

写前面几个测试方法时,可以将它们全部放置到单个测试用例类上面。随着测试方法数量的增加,很可能要分离测试用例类,让每个类只有一个测试用例类,这样就减少了每个类中测试方法的数量。随着这些测试用例类不断增大,通常要进一步分离这些类。在这种情况下,就要决定将哪些测试方法包含在每个测试用例类中。

TestcaseCla 创建 夹具 A testMethod_A_1 testMethod_A_2 执行 feature_1 SUT Cla 执行 feature_2 testMethod_B_1 testMethod_B_2 创建 夹具 B

图12-2 具有单个测试用例类的产品类。使用每个类一个测试用例类模式,单个测试用例类

保存SUT类的所有行为的全部测试方法。每个测试方法需要创建不同的夹具,要么 是内联夹具,要么是将任务委托给创建方法

12.4.2 每种特征一个测试用例类

有一种想法是将验证SUT特殊特征的所有测试方法(这里“特征”定义为共同实现SUT某种性能的一个或多个方法或属性)放置到单个测试用例类,如图12-3所示。这样很容易理解该特征的所有测试条件(使用合适的测试命名约定有助于实现这一澄清目的)。然而,它会导致每个测试用例类中需要类似的夹具建立码。

第Ⅰ部分

Feature1TestcaseCla 创建 夹具A testMethod_A testMethod_B 执行 特征_1 SUT Cla Feature2TestcaseCla 执行 特征_2 testMethod_A testMethod_B 创建 夹具B

图12-3 具有每种特征一个测试用例类的产品类。使用每种特征一个测试用例类模式时,SUT类

支持的每种主要性能或特征只有一个测试用例类。在该测试类上的测试方法在建立它们 需要的测试夹具之后执行该特征的各个方面

12.4.3 每个夹具一个测试用例类

相反的观点是,应该将所有需要相同测试夹具(相同前置条件)的测试方法分组为每个夹具一个测试用例类,如图12-4所示。这有利于将测试夹具建立码放置到setUp方法(参见“隐式建立”),但也可能导致横跨多个测试用例类的每种特征的测试条件的分散。

FeatureATestcaseCla setUp testMethod_1 testMethod_2 执行 创建 夹具A 特征_1 SUT Cla FeatureBTestcaseCla setUp testMethod_1 testMethod_2 执行 特征_2 创建 夹具B

图12-4 具有每个夹具一个测试用例类的产品类。使用每个夹具一个测试用例类模式时,SUT类的每个可能测试夹具(测试前置条件)只有一个测试用例类。该测试类上的测试方法从公 共起点执行各种特征

第12章

组 织 测 试

115

12.4.4 选择测试方法组织策略

很明显,没有可以遵循的单个“最佳实践”,最佳实践就是最适合于特定环境的实践。当为有状态的对象写单元测试,并且需要在对象的所有状态下测试每个方法时,通常使用每个夹具一个测试用例类。写服务门面的客户测试时,使用每种特征一个测试用例类就比较合适,它能够将客户可认识的特征的所有测试放在一起。当依赖预制夹具时也通常使用这种模式,因为不是每个测试中都需要夹具建立逻辑。当每个测试需要略有不同的夹具时,正确的答案是选择每种特征一个测试用例类模式,并使用委托建立来帮助建立夹具。

12.5 测试命名约定

给测试用例类和测试方法起的名称至关重要,它能够让测试易于被发现和理解。按照测试方法验证的测试条件系统命名每种测试方法,这样可以让测试覆盖更加明显。不管使用哪种测试方法组织方案,都要结合测试程序包的名称、测试用例类的名称及测试方法的名称来至少传达下列信息:

    SUT类的名称

执行的方法或特征的名称

与SUT执行相关的所有输入值的重要特征 与SUT状态或其依赖相关的所有信息

这些项是测试条件的“输入”部分。很明显,即使只在两个名称内通信也很困难,但如果实现了,回报也很高。只要在IDE的大纲视图中查看类和方法的名称,就可以知道测试的是什么测试条件。图12-5是一个示例。

图12-5同时说明包含测试条件的“异常”是多么有用:

  执行SUT时的预期输出(响应)SUT及其依赖的预期执行后状态

这种信息可以包含在测试方法的名称中(在测试方法之前添加should)。如果这种命名法让名称太长3,那么通过查看测试方法的主体总是可以访问预期结果。许多xUnit变体鼓励所有的测试方法名称用test打头,从而可以自动检测这些方法,并将它们自动添加到测试套件对象。与通过方法属性或注释表示测试方法的变体比较而言,这在某种程度上限制了命名。

第Ⅰ部分

图12-5 具有一个测试夹具一个测试用例类的产品类。使用每个夹具一个测试用例类模式时,类名称可以描述夹具,可用的方法名称用来描述输入和预期输出

12.6 组织测试套件

当测试用例类返回包含测试用例对象集合(每个测试用例对象表示一个测试方法)的测试套件对象时,它就是测试套件工厂(参见“测试枚举”)。这是xUnit提供的默认组织机制。大多数测试运行器通过实现工厂方法(Factory Method [GOF])来让任何类作为测试套件工厂,这种方法通常称为suite。

Testcase Cla 夹具 测试套件 工厂 测试套件 Creation SUT 对象

图12-6 作为测试套件工厂的测试用例类。测试用例类默认作为测试套件工厂,产生测试运行

器执行测试所需的测试套件对象。通过提供返回包含所需测试的测试套件对象的测试 套件工厂,可以枚举想要运行的特定测试

第12章

组 织 测 试

117

12.6.1 运行测试组

通常需要运行测试组(例如,测试套件),但又不想让这个决定约束组织它们的方法。普遍的约定是为每个测试程序包创建称为AllTests的特定测试套件工厂。不过,还可以为需要一起运行的测试的任何集合创建命名测试套件。好的示例是子集套件(参见“命名测试套件”),它允许运行需要软件的那些测试,该软件部署到Web服务器(或者没有部署到Web服务器!)。至少有一个用于所有单元测试的子集套件,以及用于客户测试(它们通常需要很长时间来执行)的另一个子集套件。xUnit的有些变体支持测试选择,可以使用它代替定义子集套件。

这些运行时测试组通常反映了它们运行所需的环境。例如,可以有一个包含所有测试的子集套件,这些测试不需要数据库就可以运行,以及另一个包含所有依赖数据库的测试的子集套件。同样,可以拥有某些测试的单独子集组件,这些测试依赖或者不依赖Web服务器。如果测试程序包包含所有这些测试套件,就可以将AllTests定义为由这些子集套件组成的套件的套件(参见“测试套件对象”)。因此,添加到某个子集套件的所有测试都会在AllTests内运行,而不需要付出额外的测试维护成本。

12.6.2 运行单个测试

假设测试方法在测试用例类中失败。我们决定在特定方法(每个测试都会调用该方法)上设置断点。第一个反应可能是每次遇到断点时点击Go,直到从感兴趣的测试调用为止。一种选择是让其他测试方法失效(通过注释出),这样它们就不能运行。另一种选择是重命名其他测试方法,让xUnit测试发现机制不会将它们识别为测试。在使用方法属性或注释的xUnit变体中,可以将Ignore属性添加到测试方法。尽管Ignore方法确实提醒说忽略了一些测试,但每种方法都引入了遗漏测试(参见“产品缺陷”)这个潜在问题。在提供测试树探测器(参见“测试运行器”)的xUnit家族成员中,从测试套件层次结构的观点来看,可以只选择运行单个测试,如图12-7所示。

当这些选项都不可用时,可以使用测试套件工厂来运行单个测试。不过测试套件不是要运行存在于不同测试用例类中的测试组吗?的确如此,但这并不意味着不能将它们用于其他目的。可以定义运行特定测试的单个测试套件4(参见“命名测试套件”)。要这样做,可以调用测试用例类的构造函数,它将特定测试方法的名称作为参数。我通常称之为MyTest。

第Ⅰ部分

图12-7 显示套件中测试结构的测试树探测器。可以使用测试树探测器研究测试套件的运行时结构,运行单个测试或子套件

12.7 测试码重用

测试码复制会极大地增加编写和维护测试的成本。幸运的是,有许多重用测试逻辑的方法可用。最重要的事情是,所有重用不会破坏作为文档的测试。不推荐在不同环境中(例如,不同夹具)重用实际测试方法,因为这种类型的重用通常是在不同环境测试不同事件的灵活测试(参见“条件测试逻辑”)的标记。大多数测试码重用通过隐式建立或测试实用程序方法实现。主要例外是许多测试对测试替身的重用,考虑将它们放置在哪里时,可以将这些测试替身类作为特定类型的测试辅助类。

12.7.1 测试实用程序方法位置

xUnit的许多变体提供特定测试用例超类(通常称为TestCase),所有测试用例类应该(在某些情况下必须)直接或间接地继承该超类,如图12-8所示。如果有要在其他测试用例类中重用的测试用例类上的有用实用程序方法,那么创建一个或多个要继承的测试用例超类而不是TestCase就很有帮助。如果采取这一步,这些方法要查看SUT内各种程序包中的类型或类的话,就要很小心。根测试用例超类不应该直接依赖这些类型或类,因为这可能导致循环的依赖图。可以给每个测试程序包创建一个测试用例超类,以便让测试类依赖不循环。可能的选择是为每个域程序包创建一个测试辅助类,并将各种测试辅助类放置到合适的测试程序包中。这样,不会强迫测试用例类选择单个测试用例超类,它可以只“使用”合适的测试辅助类。

第12章

组 织 测 试

测试用例超类 测试实用程序 方法 夹具 SUT 测试辅助类 testMethod_1 testMethod_n 测试实用程序 方法 测试实用程序 方法 测试用例类

图12-8 可以放置测试实用程序方法的各个位置。主要决策标准是测试方法可重用性的所需范围

12.7.2 测试用例继承与重用

从测试用例超类继承方法最常见的用法是访问测试实用程序方法。另一种用法是在测试架构及其插件时、它有利于创建通过模板方法(Template Method [GOF])指定插件一般行为的一致测试,该模板方法调用该插件特定的子类提供的方法,而测试该插件是为了检测它的特定细节。这种场景非常少,这里就不深入讨论了,更全面的介绍请参考[FaT]。

12.8 测试文件组织

下面面临一个新问题:应该将测试用例类放在哪里?很明显,这些类应该存储在源代码库[SCM]以及产品代码里。超出这个标准,还有许多选择。选择的测试打包策略非常依赖测试环境,许多IDE包含多种约束,这些约束让某些策略不能实行。关键问题是将产品代码与测试逻辑分开,然后就能找到每个代码或功能性对应的测试。

12.8.1 内置自测

使用内置自测,测试包含有产品代码,并可以在任何时候运行。没有规定让测试和产品代码分开。许多组织要将产品代码与测试逻辑分开,因此内置自测对它们而言可能不是一个好的选择。这一点在限制内存的环境中特别重要,在那种环境中,不希望测试码占用有价值的空间。

有些开发环境鼓励将测试和产品代码放在一起。例如,SAP的ABAP Unit支持关键 120 第Ⅰ部分

字For Testing,当代码传输到产品环境中时,它告诉系统让测试失效。

12.8.2 测试程序包

如果决定将测试用例类放置到单独的测试程序包中,有几种方法可以组织它们。要让测试分开,可以将它们放置到一个或多个测试程序包,同时让它们保存在相同的源树中;也可以将它们放置到相同的逻辑程序包中,但物理上将它们存储在平行源树中。Java中通常使用后面一种方法,因为它避免了测试不能查看SUT上“受保护的程序包”方法的问题5。有些IDE迷拒绝这一方法,他们坚持程序包应该完全包含在单个文件夹或项目内。使用每种产品代码程序包下面的测试程序包时,需要使用构建时测试分离器将它们排除在产品构建之外。

12.8.3 测试依赖

不管决定用何种方法存储和管理源代码,都需要确保排除了所有产品中的测试依赖(参见“产品中的测试逻辑”),因为如果产品代码需要它们才能运行,那么即使是测试分离器也无法删除这些测试。这项要求让关注类依赖变得至关重要。也不能有任何产品中的测试逻辑,因为这意味着不能测试产品中最终运行的相同代码。第6章“测试自动化策略”详细讨论过这个问题。

12.9 接下来要讨论的问题

学习如何组织测试码之后,应该熟悉更多的测试模式。第13章“使用数据库的测试”将介绍这些模式。Java提供另一种方法来解决可见性问题:可以定义自己的测试安全管理器(Security Manager),允许测试访问中SUT上的所有方法,而不只是“受保护的程序包”方法。这种方法以一般方法解决了这个问题,但需要很好理解Java类装载器。其他语言没有相同的功能性(或问题)!

下载组织测试word格式文档
下载组织测试.doc
将本文档下载到自己电脑,方便修改和收藏。
点此处下载文档

文档为doc格式

相关专题 测试组织 组织 测试
    热门文章
      整站推荐
        点击下载本文