此模块提供了一个测试框架,并在测试规范的官方套件中使用。它的所有函数都发出符合Test Anything Protocol的输出。
另请参阅在 Raku 中编写和运行测试。
方法§
子程序 plan§
multi plan(Cool :skip-all()!)multi plan()
指定测试数量——通常写在测试文件的开头。
plan 15; # expect to run 15 tests
在subtest
中,plan
用于指定子测试中的测试数量。
如果使用了plan
,则不必使用done-testing
指定测试结束。
您还可以提供一个:skip-all
命名参数来代替测试计数,以指示您要跳过所有测试。这样的计划将调用exit
,除非在subtest
内部使用。
plan :skip-all<These tests are only for Windows> unless .is-win;plan 1;ok dir 'C:/'; # this won't get run on non-Windows
如果在subtest
中使用,它将从该subtest
的Callable
中return
。因此,要在subtest
内部使用:skip-all
,您必须使用sub
而不是常规块
plan 2;subtest "Some Windows tests" => subok 42; # this will run everywhere and isn't affected by skip-all inside subtest
请注意,带有:skip-all
的plan
是为了避免执行任何测试而不将测试运行标记为失败(即计划不运行任何内容,这很好)。使用skip-rest
跳过所有进一步的测试,一旦运行开始(即计划运行一些测试,甚至可能运行了一些测试,但现在我们正在跳过所有剩下的测试)。使用bail-out
使测试运行失败,而不运行任何进一步的测试(即情况非常糟糕,没有必要运行任何其他内容;我们失败了)。
子程序 done-testing§
sub done-testing()
指定测试已完成。当您没有包含要运行的测试数量的plan
时,请使用此函数。使用done-testing
时不需要plan
。
建议在所有测试最终确定后,删除done-testing
函数并用plan
函数替换它。使用plan
可以帮助检测出由于测试中的错误或编译器中的错误而意外跳过的测试,否则不会报告测试失败。例如
sub do-stuff ;use Test;ok .is-prime for do-stuff;done-testing;# output:1..0
上面的示例是done-testing
失败的地方。do-stuff()
没有返回任何内容,也没有测试任何内容,即使它应该返回结果进行测试。但测试套件不知道应该运行多少个测试,所以它通过了。
添加 plan
可以真实反映测试
sub do-stuff ;use Test;plan 1;ok .is-prime for do-stuff;# output:1..1# Looks like you planned 1 test, but ran 0
请注意,保留 done-testing
不影响新测试结果,但应将其删除以提高清晰度。
如果任何测试失败或运行的测试少于计划,则 done-testing
函数返回 False
,否则返回 True
。
子 ok§
multi ok(Mu , = '')
如果给定的 $cond
评估为 True
,则 ok
函数将测试标记为通过。它还接受可选的测试描述作为第二个参数。
my ; my ; ...;ok .success, 'HTTP response was successful';
原则上,您可以将 ok
用于每种比较测试,方法是将比较包含在传递给 $cond
的表达式中
sub factorial() ;ok factorial(6) == 720, 'Factorial - small integer';
但是,如果可能的话,最好使用下面专门的比较测试函数之一,因为如果比较失败,它们可以打印更有用的诊断输出。
子 nok§
multi nok(Mu , = '')
如果给定的 $cond
评估为 False
,则 nok
函数将测试标记为通过。它还接受可选的测试描述作为第二个参数。
my ; my ; ...;nok .error, 'Query completed without error';
子 is§
multi is(Mu , Mu , = '')multi is(Mu , Mu , = '')
如果 $got
和 $expected
使用 eq
运算符 进行比较,则将测试标记为通过,除非 $expected
是类型对象,在这种情况下,将使用 ===
运算符;接受可选的测试描述作为最后一个参数。
注意:eq
运算符对操作数进行字符串化,这意味着 is()
不是用于测试更复杂内容(例如列表)的良好函数:is (1, (2, (3,))), [1, 2, 3]
通过测试,即使操作数有很大不同。对于这些情况,请使用 is-deeply
例程
my ; sub factorial() ; ...;is .author, "Joe", 'Retrieving the author field';is factorial(6), 720, 'Factorial - small integer';my Int ;is , Int, 'The variable $a is an unassigned Int';
注意:如果值之间仅空格不同,则 is()
将以不同的方式输出失败消息,以显示每个值中的空格。例如,在下面的输出中,第二个测试在 got:
行中显示了文字 \t
is "foo\tbar", "foo\tbaz"; # expected: 'foo baz'# got: 'foo bar'is "foo\tbar", "foo bar"; # expected: "foo bar"# got: "foo\tbar"
子 isnt§
multi isnt(Mu , Mu , = '')multi isnt(Mu , Mu , = '')
如果 $got
和 $expected
使用与 is()
相同的规则不相等,则将测试标记为通过。该函数接受可选的测试描述。
isnt pi, 3, 'The constant π is not equal to 3';my Int = 23;= Nil;isnt , Nil, 'Nil should not survive being put in a container';
子 is_approx§
multi is_approx(Mu , Mu , = '')
注意:已在 Rakudo 2023.09 版本中移除,在较早版本中已弃用。请改用 is-approx
。
子 is-approx§
multi is-approx(Numeric , Numeric , = '')
multi is-approx(Numeric , Numeric , Numeric ,= '')
multi is-approx(Numeric , Numeric , = '',Numeric : is required)
multi is-approx(Numeric , Numeric , = '',Numeric : is required)
multi is-approx(Numeric , Numeric , = '',Numeric : is required,Numeric : is required)
如果 $got
和 $expected
数值彼此近似相等,则将测试标记为通过。子例程可以用多种方式调用,这些方式允许您使用不同值的相对公差 ($rel-tol
) 或绝对公差 ($abs-tol
) 进行测试。
如果没有设置公差,则该函数将基于 $expected
的绝对值来确定公差:如果它小于 1e-6
,则使用 1e-5
的绝对公差;如果它更大,则使用 1e-6
的相对公差。
my Numeric (, , , ) = ...is-approx , ;is-approx , , 'test description';is-approx , , ;is-approx , , , 'test description';is-approx , , :;is-approx , , :, 'test description';is-approx , , :;is-approx , , :, 'test description';is-approx , , :, :;is-approx , , :, :, 'test description';
绝对公差§
当设置绝对公差时,它将用作第一个和第二个参数可以不同的实际最大值。例如
is-approx 3, 4, 2; # successis-approx 3, 6, 2; # failis-approx 300, 302, 2; # successis-approx 300, 400, 2; # failis-approx 300, 600, 2; # fail
无论给定什么值,它们之间的差值都不能大于 2
。
相对容差§
当设置相对容差时,测试将检查值之间的相对差值。给定相同的容差,给定的数字越大,它们可以相差的值就越大。
例如
is-approx 10, 10.5, :rel-tol<0.1>; # successis-approx 10, 11.5, :rel-tol<0.1>; # failis-approx 100, 105, :rel-tol<0.1>; # successis-approx 100, 115, :rel-tol<0.1>; # fail
两个版本都使用 0.1
作为相对容差,但第一个可以相差大约 1
,而第二个可以相差大约 10
。用于计算差值的函数是
|value - expected| rel-diff = ──────────────────────── max(|value|, |expected|)
如果 rel-diff
高于 $rel-tol
,则测试将失败。
同时指定绝对容差和相对容差§
is-approx , , :rel-tol<.5>, :abs-tol<10>;
当同时指定绝对容差和相对容差时,将独立测试每个容差,并且只有当两个容差都通过时,is-approx
测试才会成功。
sub is-approx-calculate§
sub is-approx-calculate(, , where ,where , )
这是当指定绝对容差和相对容差时 is-approx
调用的实际例程。它们独立测试,并且只有当两个测试都通过时,测试才会成功。
sub is-deeply§
multi is-deeply(Seq , Seq , = '')multi is-deeply(Seq , Mu , = '')multi is-deeply(Mu , Seq , = '')multi is-deeply(Mu , Mu , = '')
如果第一个和第二个参数相等,则标记测试为通过,使用与 eqv 运算符 相同的语义。这是检查(深度)数据结构相等性的最佳方法。该函数接受最后一个参数作为测试的可选描述。
use Test;plan 1;sub string-info(Str() )is-deeply string-info('42 Butterflies ♥ Raku'), Map.new((:21length,char-counts => Bag.new-from-pairs: ( :15letters, :2digits, :4other, ))), 'string-info gives right info';
注意:由于 历史原因,is-deeply
的 Seq
:D
参数通过调用 .cache
转换为 List
。如果您想确保严格的 Seq
比较,请改用 cmp-ok $got, 'eqv', $expected, $desc
。
sub cmp-ok§
multi cmp-ok(Mu is raw, , Mu is raw, = '')
使用给定的 $op
比较器比较 $got
和 $expected
,如果比较产生 True
值,则通过测试。测试描述是可选的。
$op
比较器可以是 Callable
或包含中缀运算符(例如 '=='
、'~~'
或用户定义的中缀)的 Str
。
cmp-ok 'my spelling is apperling', '~~', /perl/, "bad speller";
元运算符不能作为字符串给出;请将其作为 Callable
传递
cmp-ok <a b c>, &[!eqv], <b d e>, 'not equal';
Callable
$op
允许您使用自定义比较
sub my-comp ;cmp-ok 1, , 2, 'the dice giveth and the dice taketh away'cmp-ok 2, -> , , 7,'we got primes, one larger than the other!';
sub isa-ok§
multi isa-ok(Mu , Mu , = "The object is-a '$type.raku()'")
如果给定的对象 $var
是给定 $type
的子类或继承自给定 $type
,则标记测试为通过。为了方便,类型也可以指定为字符串。该函数接受测试的可选描述,默认为描述对象的字符串。
is Womblemy = GreatUncleBulgaria.new;isa-ok , Womble, "Great Uncle Bulgaria is a womble";isa-ok , 'Womble'; # equivalent
请注意,与 isa
不同,isa-ok
也匹配 Roles
say 42.isa(Numeric); # OUTPUT: «False»isa-ok 42, Numeric; # OUTPUT: «ok 1 - The object is-a 'Numeric'»
sub can-ok§
multi can-ok(Mu , Str , = "..." )
如果给定的 $var
可以运行名为 $meth
的方法,则标记测试为通过。该函数接受可选描述。例如
my = Womble.new;# with automatically generated test descriptioncan-ok , 'collect-rubbish';# => An object of type 'Womble' can do the method 'collect-rubbish'# with human-generated test descriptioncan-ok , 'collect-rubbish', "Wombles can collect rubbish";# => Wombles can collect rubbish
sub does-ok§
multi does-ok(Mu , Mu , = "...")
如果给定的 $var
可以执行给定的角色 $type
,则标记测试为通过。该函数接受测试的可选描述。
# create a Womble who can inventis Womble does Invent# ... and later in the testsuse Test;my = Tobermory.new;# with automatically generated test descriptiondoes-ok , Invent;# => The object does role Typedoes-ok , Invent, "Tobermory can invent";# => Tobermory can invent
子例程 like§
sub like(Str() , Regex , = "text matches $expected.raku()")
以这种方式使用
like 'foo', /fo/, 'foo looks like fo';
如果第一个参数(强制转换为字符串时)与指定为第二个参数的正则表达式匹配,则将测试标记为通过。该函数接受测试的可选描述,其默认值打印预期的匹配项。
子例程 unlike§
multi unlike(Str() , Regex , = "text does not match $expected.raku()")
以这种方式使用
unlike 'foo', /bar/, 'foo does not look like bar';
如果第一个参数(强制转换为字符串时)不与指定为第二个参数的正则表达式匹配,则将测试标记为通过。该函数接受测试的可选描述,其默认值为打印不匹配的文本。
子例程 use-ok§
multi use-ok(Str , = "$code module can be use-d ok")
如果给定的 $module
正确加载,则将测试标记为通过。
use-ok 'Full::Qualified::ModuleName';
由于 $code
正在转换为 EVAL
,因此您还可以传递参数
use-ok 'Full::Qualified::ModuleName :my-argument';
子例程 dies-ok§
multi dies-ok(Callable , = '')
如果给定的 $code
抛出异常,则将测试标记为通过。
该函数接受测试的可选描述。
sub saruman(Bool :)dies-ok , "Saruman dies";
子例程 lives-ok§
multi lives-ok(Callable , = '')
如果给定的 $code
不抛出异常,则将测试标记为通过。
该函数接受测试的可选描述。
sub frodo(Bool :)lives-ok , "Frodo survives";
子例程 eval-dies-ok§
multi eval-dies-ok(Str , = '')
如果给定的 $string
在作为代码 eval
时抛出异常,则将测试标记为通过。
该函数接受测试的可选描述。
eval-dies-ok q[my $joffrey = "nasty";die "bye bye Ned" if $joffrey ~~ /nasty/],"Ned Stark dies";
子例程 eval-lives-ok§
multi eval-lives-ok(Str , = '')
如果给定的 $string
在作为代码 eval
时不抛出异常,则将测试标记为通过。
该函数接受测试的可选描述。
eval-lives-ok q[my $daenerys-burns = False;die "Oops, Khaleesi now ashes" if $daenerys-burns],"Dany is blood of the dragon";
子例程 throws-like§
sub throws-like(, , ?, *)
如果给定的 $code
抛出特定的异常预期异常类型 $ex_type
,则将测试标记为通过。代码 $code
可以指定为 Callable
或作为要 EVAL
的字符串。异常指定为类型对象。
如果抛出异常,它还将尝试匹配匹配器哈希,其中键是将在异常上调用的方法的名称,而值是它应该具有的通过值。例如
sub frodo(Bool :);throws-like , Exception, message => /dies/;
该函数接受测试的可选描述作为第三个位置参数。
该例程使 Failure
s 致命。如果您希望避免这种情况,请使用 no fatal
pragma 并确保测试代码不会沉没可能的 Failure
s。如果您希望测试代码返回 Failure
而不是抛出,请改用 fails-like
例程。
sub fails-not-throws# test passes, even though it's just a Failure and would not always throw:throws-like , Exception;# test detects nothing thrown, because our Failure wasn't sunk or made fatal:throws-like , Exception;
请注意,仅当不引用周围作用域中的任何符号时,才能使用字符串形式(对于 EVAL
)。如果引用了,则应使用块和 EVAL 封装字符串。例如
throws-like , X::TypeCheck::Argument;
子例程 fails-like§
sub fails-like ( \test where Callable|Str, , ?, *)
与 throws-like
相同的接口,但检查代码返回 Failure
而不是抛出。如果代码确实抛出或返回的 Failure
已被 处理,则将被视为测试失败。
fails-like , X::Str::Numeric,:message(/'Cannot convert string to number'/),'converting non-numeric string to number fails';
子例程 subtest§
multi subtest(Pair )multi subtest(, )multi subtest(, = '')
subtest
函数执行给定的块,通常包含多个测试,可能包括 plan
或 done-testing
,并在 plan
、todo
或 skip
计数中算作一个测试。仅当块中的所有测试都通过时,它才会通过测试。该函数接受子测试的可选说明。
is Womblesubtest, "Check Great Uncle Bulgaria";
你还可以将说明作为第一个位置参数放置,或使用 Pair
,其中说明为键,子测试的代码为值。这对于具有大主体的子测试很有用。
subtest 'A bunch of tests',subtest 'Another bunch of tests' =>
子例程 todo§
multi todo(, = 1)
有时测试还没有准备好运行,例如某个功能可能尚未实现,在这种情况下,可以将测试标记为 todo
。或者,特定功能仅在特定平台上运行 - 在这种情况下,可以在其他平台上 skip
测试。
将 $count
个测试标记为 TODO,并给出 $reason
说明原因。默认情况下,仅一个测试将被标记为 TODO。
sub my-custom-pi ;todo 'not yet precise enough'; # Mark the test as TODO.is my-custom-pi(), pi, 'my-custom-pi'; # Run the test, but don't report# failure in test harness.
上面测试代码的结果将类似于
not ok 1 - my-custom-pi # TODO not yet precise enough # Failed test 'my-custom-pi' # at test-todo.rakutest line 7 # expected: '3.14159265358979' # got: '3'
请注意,如果你对 subtest
使用 todo
,其中所有失败的测试都将自动标记为 TODO,并且不会计入你的原始 TODO 计数。
子例程 skip§
multi skip()multi skip(, = 1)
跳过 $count
个测试,并给出 $reason
说明原因。默认情况下,仅跳过一个测试。当运行测试(或测试)会导致死机时,请使用此类功能。
sub num-forward-slashes() ;if ~~ 'linux'else
请注意,如果你将测试标记为已跳过,还必须阻止该测试运行。
子例程 skip-rest§
sub skip-rest( = '<unknown>')
跳过剩余的测试。如果测试文件中的其余测试都因某种条件而失败,请使用此函数跳过它们,并提供一个可选的 $reason
说明原因。
my ; sub womble ; ...;unless ~~ "Wimbledon Common"# tests requiring functional womblingok womble();# ...
请注意,skip-rest
需要设置 plan
,否则 skip-rest
调用将抛出错误。请注意,skip-rest
不会退出测试运行。手动执行此操作,或使用条件语句以避免运行任何进一步的测试。
另请参见 plan :skip-all('...')
以完全避免运行任何测试,以及 bail-out
以中止测试运行并将其标记为失败。
子例程 bail-out§
sub bail-out (?)
如果你已经知道测试将失败,则可以使用 bail-out()
退出测试运行
my ;...or bail-out 'Must have database connection for testing';
该函数中止当前测试运行,向测试框架发出失败信号。需要提供一个可选的退出原因。子例程将调用 exit()
,因此如果您需要执行清理,请在调用 bail-out()
之前执行。
如果您想中止测试运行,但又不将其标记为失败,请参阅 skip-rest
或 plan :skip-all('...')
子例程 pass§
multi pass( = '')
pass
函数将测试标记为通过。flunk
将测试标记为未通过。这两个函数都接受可选的测试描述。
pass "Actually, this test has passed";flunk "But this one hasn't passed";
由于这些子例程不提供有关接收到的值和预期的值的信息,因此应谨慎使用它们,例如在评估复杂测试条件时。
子例程 flunk§
multi flunk( = '')
pass
的相反操作,使测试失败,并带有可选消息。
子例程 diag§
sub diag()
在标准错误流中以与 TAP 兼容的方式显示诊断信息。通常在特定测试无法提供测试本身未提供的信息时使用。或者,它可用于提供有关测试文件测试进度(在进行压力测试时非常重要)的可视标记。
diag "Yay! The tests got to here!";