内容

名称

Test::Tester - 简化使用 Test::Builder 构建的测试模块的测试

概要

use Test::Tester tests => 6;

use Test::MyStyle;

check_test(
  sub {
    is_mystyle_eq("this", "that", "not eq");
  },
  {
    ok => 0, # expect this to fail
    name => "not eq",
    diag => "Expected: 'this'\nGot: 'that'",
  }
);

或者

use Test::Tester tests => 6;

use Test::MyStyle;

check_test(
  sub {
    is_mystyle_qr("this", "that", "not matching");
  },
  {
    ok => 0, # expect this to fail
    name => "not matching",
    diag => qr/Expected: 'this'\s+Got: 'that'/,
  }
);

或者

use Test::Tester;

use Test::More tests => 3;
use Test::MyStyle;

my ($premature, @results) = run_tests(
  sub {
    is_database_alive("dbname");
  }
);

# now use Test::More::like to check the diagnostic output

like($results[0]->{diag}, "/^Database ping took \\d+ seconds$"/, "diag");

描述

如果您编写了一个基于 Test::Builder 的测试模块,那么 Test::Tester 允许您以最少的努力对其进行测试。

使用方法 (简单方法)

从版本 0.08 开始,Test::Tester 不再要求您在测试模块中包含任何特殊内容。您只需

use Test::Tester;

在您的测试脚本中,任何其他基于 Test::Builder 的模块之前,就可以开始使用了。

其他基于 Test::Builder 的模块可以用来帮助进行测试。事实上,您甚至可以使用模块中的函数来测试同一个模块中的其他函数(虽然这在理论上是可行的,但可能不是一个好主意,如果您的模块存在错误,那么使用它来测试自身可能会得到错误的结果)。

最简单的测试方法是像这样:

check_test(
  sub { is_mystyle_eq("this", "that", "not eq") },
  {
    ok => 0, # we expect the test to fail
    name => "not eq",
    diag => "Expected: 'this'\nGot: 'that'",
  }
);

这将执行 is_mystyle_eq 测试,捕获其结果并检查它们是否符合预期。

您可能需要以更灵活的方式检查测试结果,例如,诊断输出可能很长或很复杂,或者它可能涉及您无法事先预测的内容,例如时间戳。在这种情况下,您可以直接访问测试结果。

my ($premature, @results) = run_tests(
  sub {
    is_database_alive("dbname");
  }
);

like($result[0]->{diag}, "/^Database ping took \\d+ seconds$"/, "diag");

或者

check_test(
  sub { is_mystyle_qr("this", "that", "not matching") },
  {
    ok => 0, # we expect the test to fail
    name => "not matching",
    diag => qr/Expected: 'this'\s+Got: 'that'/,
  }
);

我们无法预测数据库 ping 需要多长时间,因此我们使用 Test::More 的 like() 测试来检查诊断字符串是否具有正确的形式。

如何使用(难方法)

这仅出于向后兼容性目的而存在。

让您的模块使用 Test::Tester::Capture 对象而不是 Test::Builder 对象。如何做到这一点取决于您的模块,但假设您的模块在 $Test 中保存 Test::Builder 对象,并且所有测试例程都通过 $Test 访问它,那么提供类似这样的函数

sub set_builder
{
  $Test = shift;
}

应该允许您的测试脚本执行

Test::YourModule::set_builder(Test::Tester->capture);

之后,模块内的任何测试都将被捕获。

测试结果

每个测试的结果都存储在一个哈希中。这些哈希与 Test::Builder->details 返回的哈希相同,但包含几个额外的字段。

这些字段在 Test::Builder 的 details() 函数中进行了说明。

ok

测试是否通过?

actual_ok

测试是否真的通过?也就是说,通过是来自 Test::Builder->ok() 还是因为它是一个 TODO 测试?

name

为测试提供的名称。

type

测试类型?可能性包括跳过、todo 等。有关更多详细信息,请参阅 Test::Builder

reason

跳过、todo 等的原因。有关更多详细信息,请参阅 Test::Builder

这些字段是 Test::Tester 独有的。

diag

为测试输出的任何诊断信息。这仅包括在声明测试结果之后输出的诊断信息。

请注意,Test::Builder 确保任何诊断信息都以 \n 结尾,并且在早期版本的 Test::Tester 中,您必须在预期的诊断信息中包含最终的 \n。从版本 0.10 开始,Test::Tester 会在您忘记时添加 \n。如果您期望没有诊断信息,它不会添加 \n。有关帮助跟踪难以找到的空格和制表符相关问题,请参见下文。

depth

这允许您检查您的测试模块是否为 $Test::Builder::Level 设置了正确的值,从而在测试失败时提供正确的文件和行号。它是通过查看 caller() 和 $Test::Builder::Level 计算的。它应该计算在跳入您正在测试的函数之前有多少个子例程。例如,在

run_tests( sub { my_test_function("a", "b") } );

深度应该为 1,而在

sub deeper { my_test_function("a", "b") }

run_tests(sub { deeper() });

深度应该为 2,即子例程 {} 为 1,deeper() 为 1。这可能看起来有点复杂,但如果您的测试看起来像本文档中的简单示例,那么您无需担心,因为深度始终为 1,这是 Test::Tester 默认情况下所期望的。

注意:如果您在 check_test() 中未指定深度值,则它会自动将其与 1 进行比较,如果您确实要跳过深度测试,则传入 undef。

注意:对于从信号处理程序或 END 块或任何其他隐藏调用堆栈的地方运行的测试,深度将无法正确计算。

Test::Tester 的一些函数返回这些哈希的数组,就像 Test::Builder->details 一样。也就是说,第一个测试的哈希将是数组元素 1(而不是 0)。元素 0 将不是哈希,而是一个字符串,其中包含在第一个测试之前出现的任何诊断输出。这通常应该是空的,如果不是,则意味着在任何测试结果出现之前,某些东西输出诊断信息。

空格和制表符

外表可能是欺骗性的,尤其是在空缺方面。如果您正在挠头试图弄清楚为什么 Test::Tester 说您的诊断信息是错误的,而它们看起来完全正确,那么答案可能是空白。从版本 0.10 开始,Test::Tester 用单引号包围预期和得到的诊断值,以便更容易地发现尾随空白。因此,在这个例子中

# Got diag (5 bytes):
# 'abcd '
# Expected diag (4 bytes):
# 'abcd'

很明显第一个字符串的末尾有一个空格。解决此问题的另一种方法是在 ANSI 终端上使用颜色和反向视频,如果您需要此功能,请参见下面的颜色。

不幸的是,这有时还不够,颜色或引号都无法帮助您解决涉及制表符、其他非打印字符以及 Unicode 中某些类型的问题。为了解决这个问题,您可以将 Test::Tester 切换到一种模式,在这种模式下,所有“棘手”字符都显示为 \{xx}。棘手字符是指 ASCII 代码小于 33 或大于 126 的字符。这使得输出更难阅读,但更容易找到字符串之间的细微差异。要打开此模式,请在您的测试脚本中调用 show_space() 或将 TESTTESTERSPACE 环境变量设置为真值。上面的例子看起来像

# Got diag (5 bytes):
# abcd\x{20}
# Expected diag (4 bytes):
# abcd

颜色

如果您希望使用颜色来查找棘手的空白字符,则可以将TESTTESTCOLOUR环境变量设置为用逗号分隔的颜色对,第一个用于前景,第二个用于背景。例如,“white,red”将在红色背景上打印白色文本。这需要Term::ANSIColor模块。您可以指定Term::ANSIColor::color函数可以接受的任何颜色。

如果您拼写颜色不同,那也没问题。TESTTESTERCOLOR变量也可以使用(如果两者都设置,则英国拼写优先)。

导出函数

($premature, @results) = run_tests(\&test_sub)

\&test_sub 是一个子例程的引用。

run_tests 运行 $test_sub 中的子例程并捕获其中任何测试的结果。如果您愿意,可以在此子例程中运行多个测试。

$premature 是一个字符串,包含第一个测试之前的所有诊断输出。

@results 是一个测试结果哈希数组。

cmp_result(\%result, \%expect, $name)

\%result 是一个测试结果哈希的引用。

\%expect 是一个哈希的引用,包含测试结果的预期值。

cmp_result 将结果与预期值进行比较。如果发现任何差异,它将输出诊断信息。您可以从预期结果中省略任何字段,cmp_result 不会对该字段进行比较。

cmp_results(\@results, \@expects, $name)

\@results 是一个测试结果数组的引用。

\@expects 是一个哈希引用数组的引用。

cmp_results 检查结果是否与预期结果匹配,如果发现任何差异,它将输出诊断信息。它首先检查 \@results 和 \@expects 中的元素数量是否相同。然后,它遍历每个结果,将其与预期结果进行比较,如上面的 cmp_result() 中所述。

($premature, @results) = check_tests(\&test_sub, \@expects, $name)

\&test_sub 是一个子例程的引用。

\@expect 是一个指向哈希引用数组的引用,这些哈希引用是预期的测试结果。

check_tests 将 run_tests 和 cmp_tests 合并为一个调用。它还检查测试是否在任何阶段失败。

它返回与 run_tests 相同的值,因此您可以在需要时进一步检查测试结果。

($premature, @results) = check_test(\&test_sub, \%expect, $name)

\&test_sub 是一个子例程的引用。

\%expect 是一个指向哈希的引用,该哈希包含测试结果的预期值。

check_test 是 check_tests 的包装器。它将 run_tests 和 cmp_tests 合并为一个调用,检查测试是否失败。它假设在 \&test_sub 中只运行一个测试,并包含一个测试以确保这是真的。

它返回与 run_tests 相同的值,因此您可以在需要时进一步检查测试结果。

show_space()

打开字符转义,如“空格和制表符”部分所述。

工作原理

通常,测试模块(我们称之为 Test:MyStyle)调用 Test::Builder->new 来获取 Test::Builder 对象。Test::MyStyle 在此对象上调用方法来记录有关测试结果的信息。当加载 Test::Tester 时,它会用返回 Test::Tester::Delegate 对象的方法替换 Test::Builder 的 new() 方法。大多数情况下,此对象的行为与真正的 Test::Builder 对象相同。任何调用的方法都会委托给真正的 Test::Builder 对象,因此一切正常。但是,一旦进入测试模式,方法调用就不会再传递给真正的 Test::Builder 对象,而是传递给 Test::Tester::Capture 对象。此对象看起来与真正的 Test::Builder 对象完全相同,只是它不会输出测试结果和诊断信息,而是记录所有信息以供以后分析。

注意事项

对调用 Test::Builder->note 的支持非常有限。它被实现为空存根,因此使用它的模块不会崩溃,但这些调用不会像其他调用那样被记录以供测试目的。欢迎提供补丁。

另请参阅

Test::Builder 是测试好东西的来源。 Test::Builder::Tester 针对 Test::Tester 解决的问题提供了另一种方法 - 它捕获 Test::Builder 输出的字符串。这意味着您无法单独访问各个信息片段,并且必须准确预测您的测试将输出什么。

作者

此模块的版权为 2005 年 Fergal Daly <[email protected]>,部分内容基于其他人的作品。

计划处理从 Test::More 中提取。由 Michael G Schwern <[email protected]> 编写。

Test::Tester::Capture 是 Test::Builder 的简化和修改版本。Test::Builder 由 chromatic <[email protected]> 和 Michael G Schwern <[email protected]> 编写。

许可证

与 Perl 本身相同的许可证

参见 https://perldotcom.perl5.cn/perl/misc/Artistic.html