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() 函数中进行了说明。
测试是否通过?
测试是否真的通过?也就是说,通过是来自 Test::Builder->ok() 还是因为它是一个 TODO 测试?
为测试提供的名称。
测试类型?可能性包括跳过、todo 等。有关更多详细信息,请参阅 Test::Builder。
跳过、todo 等的原因。有关更多详细信息,请参阅 Test::Builder。
这些字段是 Test::Tester 独有的。
为测试输出的任何诊断信息。这仅包括在声明测试结果之后输出的诊断信息。
请注意,Test::Builder 确保任何诊断信息都以 \n 结尾,并且在早期版本的 Test::Tester 中,您必须在预期的诊断信息中包含最终的 \n。从版本 0.10 开始,Test::Tester 会在您忘记时添加 \n。如果您期望没有诊断信息,它不会添加 \n。有关帮助跟踪难以找到的空格和制表符相关问题,请参见下文。
这允许您检查您的测试模块是否为 $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
变量也可以使用(如果两者都设置,则英国拼写优先)。
\&test_sub 是一个子例程的引用。
run_tests 运行 $test_sub 中的子例程并捕获其中任何测试的结果。如果您愿意,可以在此子例程中运行多个测试。
$premature 是一个字符串,包含第一个测试之前的所有诊断输出。
@results 是一个测试结果哈希数组。
\%result 是一个测试结果哈希的引用。
\%expect 是一个哈希的引用,包含测试结果的预期值。
cmp_result 将结果与预期值进行比较。如果发现任何差异,它将输出诊断信息。您可以从预期结果中省略任何字段,cmp_result 不会对该字段进行比较。
\@results 是一个测试结果数组的引用。
\@expects 是一个哈希引用数组的引用。
cmp_results 检查结果是否与预期结果匹配,如果发现任何差异,它将输出诊断信息。它首先检查 \@results 和 \@expects 中的元素数量是否相同。然后,它遍历每个结果,将其与预期结果进行比较,如上面的 cmp_result() 中所述。
\&test_sub 是一个子例程的引用。
\@expect 是一个指向哈希引用数组的引用,这些哈希引用是预期的测试结果。
check_tests 将 run_tests 和 cmp_tests 合并为一个调用。它还检查测试是否在任何阶段失败。
它返回与 run_tests 相同的值,因此您可以在需要时进一步检查测试结果。
\&test_sub 是一个子例程的引用。
\%expect 是一个指向哈希的引用,该哈希包含测试结果的预期值。
check_test 是 check_tests 的包装器。它将 run_tests 和 cmp_tests 合并为一个调用,检查测试是否失败。它假设在 \&test_sub 中只运行一个测试,并包含一个测试以确保这是真的。
它返回与 run_tests 相同的值,因此您可以在需要时进一步检查测试结果。
打开字符转义,如“空格和制表符”部分所述。
通常,测试模块(我们称之为 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