如何在Test :: More子测试中抛出/捕获异常?

时间:2014-08-11 15:03:04

标签: perl exception-handling

有没有办法如何从子子测试中抛出异常(又名。dieCarp家庭成员)并能够抓住它们(又名。evallives_ok在Perl 5.10中的父子测试中?

我想在for循环中运行一组测试,如下所示:

use Test::More;
use Test::Exception;

for (my $i=0; $i<=2; $i++) {
    subtest("outer $i" => sub {
        lives_ok(sub {
            inner();
        }, "lives_ok");
        done_testing();
    });
    note("Outer code should continue regardless of exceptions in inner().\n");
}

我调用的inner()测试可以在子测试中死掉,例如:

sub inner {
    subtest("inner" => sub {
        ok(1, 'ok');
        die("EXCEPTION message here");
        note("This code should NOT be reached\n");
        done_testing();
    });
}

inner子测试结束时,我希望能够继续进行下一次外部测试。但是,在上面的例子中,外部测试也会死掉,lives_ok对我的问题没用:

        ok 1 - ok
        # Child (inner) exited without calling finalize()
    not ok 1 - inner
    not ok 2 - lives_ok
    1..2
    #   Failed test 'inner'
    #   Failed test 'lives_ok'
    # died: EXCEPTION message here at ...
    # Child (outer 0) exited without calling finalize()
not ok 1 - outer 0
#   Failed test 'outer 0'
# ---------------
# Can't call finalize() with child (inner) active at Test/Builder.pm line 229.
# ---------------
# Tests were run but no plan was declared and done_testing() was not seen.

在现实生活中inner实际上会调用许多可能死亡的函数,因此我正在寻找一种只涉及更改outer循环的解决方案。

如果那是不可能的,我将不得不eval(又名。lives_ok)所有内部子测试中可能死亡的每个语句,我怎样才能避免嵌套测试是否{{ 1}}通过与否?

lives_ok

编辑:每个循环可以有100个TAP输出行,所以我确实想使用嵌套的子测试

2 个答案:

答案 0 :(得分:1)

在子测试中发生未被捕获的异常(从而导致子测试的coderef过早结束)被Test :: More / Test :: Builder视为错误,因此它会出现恐慌和失败。

在这个特定的例子中,我建议可能不需要嵌套第二级子测试。 inner可以改写为:

sub inner {
#   subtest("inner" => sub {
        ok(1, 'ok');
        die("EXCEPTION message here");
        note("This code should NOT be reached\n");
#       done_testing();
#   });
}

...然后您的整个测试脚本将运行。 (当然,由于lives_ok测试,测试失败了。)

答案 1 :(得分:0)

除非有人建议更好的解决方案,否则我将重构一下并使用这种解决方法 - 永远不要直接死在子测试中,并调用所有可能在子测试中使用lives_ok而死的函数。

使用问题中的示例:

sub inner {
    subtest("inner" => sub {
        ok(1, 'ok');
        $err = "EXCEPTION message here";
        if (not $err) {
            note("This code should NOT be reached\n");
        }
        done_testing();
    });
    confess($err) if $err;
}