目前我正在创建这样的事务测试:
use Test::More;
use Try::Tiny;
my $dbh = ...;
subtest 'do something envolving a transaction' => sub {
$dbh->begin_work();
try {
my $obj = create_in_db({...}, $dbh);
my $result = MyTestObject->new()->do_something($obj);
ok $result "We've got great results";
} catch {
croak $_;
} finally {
$dbh->rollback(); #kills $obj
};
};
done_testing();
1;
这可行,但有一个缺点,即错误行始终是 catch 块和子测试的末尾,而不是错误实际发生的位置。而且很快就会有很多无聊的样板代码。
如何以更聪明的方式做到这一点?
事实上,错误 (
croak
) 是在 try-catch-finally
块† 的末尾报告的,而不是在调用有问题的代码的地方,这似乎是由于 Try::Tiny
与命名空间的混淆所致;请参阅这篇文章中的讨论和评论。在复杂的 try 子中,我不清楚这种不当行为的确切来源。一个简单的演示
use warnings;
use strict;
use feature 'say';
use Carp qw(croak);
use Try::Tiny;
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 8
try {
this_croaks(); # line 11
}
catch { print "In try: $_" }
finally { say "clean up" }; # line 14
此打印
在尝试中:来自 try_tiny_mixup.pl 第 14 行 main 中的子程序。 清理
但是
croak
-ing 子函数是在第 11 行调用的,因此应该报告它,而不是第 14 行。‡
将
croak
更改为 die
会打印 line 8
(这当然不是解决方案),同时使用 eval
而不是 Try::Tiny
会打印出正确的 line 11
(什么是有效的解决方案) 。请参阅链接的帖子。我不知道 Try::Tiny
是否有修复,但有直接替代品,请参见下文。
我不认为这以任何方式取决于执行的测试(正如我们所知,这里涉及数据库事务)。如果没有可运行的示例,我无法更具体地检查。
最有效的一件事是恢复到
eval
,从 5.14 开始,它不再带有 Try::Tiny
所声明原因的微妙之处。喜欢eval {
this_croaks();
};
if ($@) {
print "In eval: $@";
}
say "clean up";
这仍然是过时的,但它的工作原理正如预期的那样(并且
Try::Tiny
带有自己的
扭曲)。 希望即将推出的原生 try/catch
(在 5.34.0 中作为 实验性引入)不会出现这样的问题。§ 目前还没有
use warnings;
use v5.34.0;
use Carp qw(croak);
use experimental 'try';
sub this_croaks { croak "ouch from a sub in ", __PACKAGE__ } # line 9
try {
this_croaks(); # line 12
}
catch ($e) {
print "In try: $e";
}
say "clean up"; # there is no "finally" keyword (see text and links)
(The pragma [experimental](https://perldoc.perl.org/experimental) replaces the otherwise needed two statements for using experimental features.)
这正确地将其固定在第 12 行(来自第 9 行)。请注意,目前还没有
finally
关键字。模块
Syntax::Keyword::Tiny
(参见脚注)确实有它,因此可以使用它作为 Try::Tiny
的直接替代品。我怀疑清除这个问题也会清除测试的行为。 (但我没有测试过。)
匿名子句的语法辅助(“糖”)(在很多方面并不那么幼稚)
‡提交了错误报告
§这是作者自己从 Syntax::Keyword::Try 移植的,所以你可能想尝试一下 - 但最好使用 Feature::Compat::Try,他们说。请参阅两者的文档,并查看其跟踪器。 一旦我们进行实验,请参阅
perexperiment