查看源代码 入门指南

新手入门

本节的目的是让新手通过“示例学习”的方式快速开始编写和执行一些简单的测试。大部分解释将留到后面的章节。如果您不热衷于“示例学习”,而更喜欢技术细节,请直接跳到下一节。

本节演示了编写一个基本的(但对于许多模块测试目的而言,通常足够复杂)测试套件并执行其测试用例是多么简单。当您阅读本用户指南的其余章节时,这不一定很明显。

注意

为了理解这里讨论和举例的内容,我们建议您首先阅读Common Test 基础一节。

测试用例执行

测试用例的执行方式如下:

Successful and Unsuccessful Test Case Execution

对于 Common Test 被命令执行的每个测试用例,它都会生成一个专用进程,该进程将启动测试用例函数。(与测试用例进程并行,会启动一个空闲等待计时器进程,该进程链接到测试用例进程。如果计时器进程耗尽等待时间,它会发送一个退出信号以终止测试用例进程。这被称为超时陷阱)。

在情景 1 中,测试用例进程在 case A 完成执行其测试代码且未检测到任何错误后正常终止。测试用例函数返回一个值,并且 Common Test 将该测试用例记录为成功。

在情景 2 中,在测试 case B 执行期间检测到错误。这会导致测试 case B 函数生成一个异常,结果导致测试用例进程以非正常原因退出。Common Test 将此记录为不成功(失败)的测试用例。

正如您从图中理解的那样,Common Test 要求测试用例生成运行时错误来指示失败(例如,通过导致错误的匹配错误或通过调用 exit/1,最好通过辅助函数 ct:fail/1,2)。成功执行由测试用例函数的正常返回指示。

一个简单的测试套件

Common Test 基础 一节所示,测试套件模块为各种目的实现 回调函数(强制或可选),例如:

  • 测试套件的初始化/结束配置函数
  • 测试用例的初始化/结束配置函数
  • 测试用例组的初始化/结束配置函数
  • 测试用例

配置函数是可选的。以下示例是一个没有配置函数的测试套件,包括一个简单的测试用例,用于检查模块 mymod 是否存在(即,是否可以被代码服务器成功加载)

-module(my1st_SUITE).
-compile(export_all).

all() ->
    [mod_exists].

mod_exists(_) ->
    {module,mymod} = code:load_file(mymod).

如果操作失败,则会发生错误匹配错误,从而终止测试用例。

带有配置函数的测试套件

如果您需要执行配置操作来运行测试,可以在套件中实现配置函数。配置函数的结果是配置数据或 Config。这是一个键值元组列表,这些元组从配置函数传递到测试用例(可能通过“较低级别”的配置函数)。数据流如下所示:

Configuration Data Flow in a Suite

以下示例显示了一个使用配置函数为测试用例打开和关闭日志文件的测试套件(这是一个每个测试用例执行都不必要且不相关的操作)

-module(check_log_SUITE).
-export([all/0, init_per_suite/1, end_per_suite/1]).
-export([check_restart_result/1, check_no_errors/1]).

-define(value(Key,Config), proplists:get_value(Key,Config)).

all() -> [check_restart_result, check_no_errors].

init_per_suite(InitConfigData) ->
    [{logref,open_log()} | InitConfigData].

end_per_suite(ConfigData) ->
    close_log(?value(logref, ConfigData)).

check_restart_result(ConfigData) ->
    TestData = read_log(restart, ?value(logref, ConfigData)),
    {match,_Line} = search_for("restart successful", TestData).

check_no_errors(ConfigData) ->
    TestData = read_log(all, ?value(logref, ConfigData)),
    case search_for("error", TestData) of
        {match,Line} -> ct:fail({error_found_in_log,Line});
        nomatch -> ok
    end.

测试用例通过解析日志文件来验证我们的 SUT 是否已成功重启,并且没有打印出意外的错误。

要在最近的测试套件中执行测试用例,请在 UNIX/Linux 命令行上键入以下内容(假设套件模块位于当前工作目录中):

$ ct_run -dir .

$ ct_run -suite check_log_SUITE

要使用 Erlang shell 运行我们的测试,您可以评估以下调用:

1> ct:run_test([{dir, "."}]).

1> ct:run_test([{suite, "check_log_SUITE"}]).

运行测试的结果将以 HTML 格式打印在日志文件中(存储在不同级别的唯一日志目录中)。下图显示了日志文件结构:

HTML Log File Structure

问题与解答

以下是一些您在阅读本节后可能遇到的问题,以及相应的提示和答案链接:

  • 问题: “我可以在哪里以及如何为我的测试指定变量数据,而这些数据不能在测试套件中硬编码(例如主机名、地址和用户登录数据)?”

    答案: 请参阅 外部配置数据 一节。

  • 问题: “有没有办法声明不同的测试并在一个会话中运行它们,而无需编写自己的脚本?此外,这些声明是否可以用于回归测试?”

    答案: 请参阅运行测试和分析结果中的 测试规范 一节。

  • 问题: “测试用例和/或测试运行是否可以自动重复?”

    答案: 了解有关 测试用例组 的更多信息,并阅读有关 运行测试 一节和参考手册中的启动标志/选项。

  • 问题:Common Test 是按顺序还是并行执行我的测试用例?”

    答案: 请参阅编写测试套件中的 测试用例组

  • 问题: “什么是超时陷阱(前面提到)的语法,以及如何设置它们?”

    答案: 这在编写测试套件的 超时陷阱 部分中进行了解释。

  • 问题: “有哪些可用于日志记录和打印的函数?”

    答案: 请参阅编写测试套件中的 日志记录

  • 问题: “我的测试需要数据文件。最好将它们存储在哪里?”

    答案: 请参阅 数据和私有目录

  • 问题: “可以给我一个测试套件示例吗?”

    答案: 欢迎!

您可能想现在开始自己的第一个测试套件,同时深入研究 Common Test 用户指南和参考手册。关于本节中介绍的内容还有很多需要学习的地方。还有许多其他有用的功能需要学习,所以请继续阅读其他章节,并尽情享受吧。