查看源代码 通用测试基础

概述

Common Test 框架是一个支持实现和自动化执行针对任何类型目标系统的测试用例的工具。Common Test 是 Erlang/OTP 系统开发和维护中所有测试和验证活动的主要工具。

测试用例可以单独执行或批量执行。Common Test 还具有分布式测试模式,带有中央控制和日志记录。借助此功能,可以在一个公共会话中独立测试多个系统。例如,在运行自动化大规模回归测试时,这非常有用。

被测系统 (SUT) 可以由一个或多个目标节点组成。Common Test 包含一个通用测试服务器,该服务器与其他测试实用程序一起用于执行测试用例。测试可以从 GUI、操作系统 shell 或 Erlang shell 启动。测试套件是包含要执行的测试用例(Erlang 函数)的文件(Erlang 模块)。支持模块提供测试用例用来进行测试的函数。

在黑盒测试场景中,基于 Common Test 的测试程序通过标准 O&M 和 CLI 协议连接到目标系统。Common Test 提供了其中一些协议的实现和包装器接口(其中大多数作为独立的组件和应用程序存在于 OTP 中)。包装器简化了配置,并增加了日志记录的详细程度。Common Test 不断扩展有用的支持模块。但是,请注意,使用任何 Erlang/OTP 组件进行 Common Test 的测试非常简单,无需 Common Test 的包装器。它就像调用 Erlang 函数一样简单。Common Test 中支持许多与目标无关的接口,例如通用 Telnet 和 FTP。这些可以专门化或直接用于控制仪器、流量负载生成器等。

Common Test 也是白盒测试 Erlang 代码(例如,模块测试)的非常有用的工具,因为测试程序可以直接调用导出的 Erlang 函数。实现基本测试套件和执行简单测试所需的开销非常小。对于黑盒测试 Erlang 软件,可以使用 Erlang RPC 和标准 O&M 接口等。

测试用例可以并行处理与一个或多个目标系统、仪器和流量生成器的多个连接,以执行测试所需的必要操作。并行处理多个连接是 Common Test 的主要优势之一,这得益于 Erlang 运行时系统中对并发性的有效支持,Common Test 用户可以充分利用这一点。

测试套件组织

测试套件在测试目录中组织,并且每个测试套件可以具有单独的数据目录。通常,这些文件和目录与其他的源代码形式(可能是通过诸如 GIT 或 Subversion 之类的版本控制系统)进行版本控制。但是,Common Test 本身不对可能的文件和目录版本有任何要求(或没有任何意识)。

支持库

支持库包含对所有测试套件或特定功能区域或子系统中的测试套件有用的函数。除了 Common Test 框架提供的通用支持库以及 Erlang/OTP 提供的各种库和应用程序之外,还可能需要定制的(用户特定的)支持库。

套件和测试用例

测试是通过运行测试套件(测试用例集)或单独的测试用例来执行的。测试套件实现为名为 <suite_name>_SUITE.erl 的 Erlang 模块,其中包含多个测试用例。测试用例是测试一个或多个事项的 Erlang 函数。测试用例是 Common Test 测试服务器处理的最小单元。

也可以定义称为测试用例组的测试用例集。测试用例组可以具有与其关联的执行属性。执行属性指定组中的测试用例是以随机顺序、并行还是顺序执行,以及组的执行是否重复。测试用例组也可以嵌套(即,除了测试用例之外,组还可以包含子组)。

除了测试用例和组之外,测试套件还可以包含配置函数。这些函数旨在用于设置(和验证)SUT(和/或 Common Test 主机节点)中的环境和状态,以便测试可以正确执行。操作示例包括:打开与 SUT 的连接、初始化数据库、运行安装脚本等。可以按套件、按测试用例组以及按单独的测试用例执行配置。

测试套件模块必须符合 Common Test 测试服务器指定的回调接口。有关详细信息,请参见编写测试套件部分。

如果测试用例返回到调用者,则无论返回的值是什么,都被认为是成功的。但是,以下几个返回值具有特殊含义

  • {skip,Reason} 表示跳过测试用例。
  • {comment,Comment} 在测试用例的日志中打印注释。
  • {save_config,Config} 使 Common Test 测试服务器将 Config 传递给下一个测试用例。

无论终止的原因是什么,测试用例失败都被指定为运行时错误(崩溃)。如果有效地使用 Erlang 模式匹配,则可以利用此属性。结果是简洁且可读的测试用例函数,看起来更像是脚本而不是实际程序。一个简单的例子

session(_Config) ->
    {started,ServerId} = my_server:start(),
    {clients,[]} = my_server:get_clients(ServerId),
    MyId = self(),
    connected = my_server:connect(ServerId, MyId),
    {clients,[MyId]} = my_server:get_clients(ServerId),
    disconnected = my_server:disconnect(ServerId, MyId),
    {clients,[]} = my_server:get_clients(ServerId),
    stopped = my_server:stop(ServerId).

随着测试套件的运行,所有信息(包括对 stdout 的输出)都会记录在许多不同的日志文件中。用户控制台中显示的最少信息(仅开始和停止信息,以及每个失败的测试用例的注释)。

每个测试用例的结果都记录在为特定测试运行创建的专用 HTML 日志文件中。概述页面显示每个测试用例,该测试用例由表格行表示,显示总执行时间、用例是否成功、失败或跳过以及可选的用户注释。对于失败的测试用例,终止的原因也会打印在注释字段中。概述页面具有指向每个测试用例日志文件的链接,从而可以使用任何标准 HTML 浏览器轻松导航。

注意

在最后一行显示总计的行中,此处显示的时间是上方各行的总和(不考虑并行测试用例)。另一方面,“经过时间”是运行测试用例所花费的时钟时间。

外部接口

Common Test 测试服务器要求测试套件定义并导出以下强制性或可选的回调函数

  • all() - 返回套件中所有测试用例和组的列表。(强制性)

  • suite() - 用于返回套件属性的信息函数。(可选)

  • groups() - 用于声明测试用例组。(可选)

  • init_per_suite(Config) - 套件级别的配置函数,在第一个测试用例之前执行。(可选)

  • end_per_suite(Config) - 套件级别的配置函数,在最后一个测试用例之后执行。(可选)

  • group(GroupName) - 用于返回测试用例组属性的信息函数。(可选)

  • init_per_group(GroupName, Config) - 组的配置函数,在第一个测试用例之前执行。(可选)

  • end_per_group(GroupName, Config) - 组的配置函数,在最后一个测试用例之后执行。(可选)

  • init_per_testcase(TestCase, Config) - 测试用例的配置函数,在每个测试用例之前执行。(可选)

  • end_per_testcase(TestCase, Config) - 测试用例的配置函数,在每个测试用例之后执行。(可选)

对于每个测试用例,Common Test 测试服务器期望以下函数

  • Testcasename() - 返回测试用例属性列表的信息函数。(可选)

  • Testcasename(Config) - 测试用例函数。