如何测试::更多、更智能的交易?

发布于 2025-01-09 13:27:56 字数 594 浏览 0 评论 0原文

目前我正在创建这样的事务测试:

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 块和子测试的末尾,而不是错误实际发生的位置。而且很快就会有很多无聊的样板代码。

如何以更聪明的方式做到这一点?

Currently I am creating transactional tests like that:

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;

This works, but has the disadvantage, that the line of the error is always the catch block and the end of the subtest, never where the error actually happens. And it is a lot of boring boilerplate code that quickly adds up.

How to do this in a smarter way?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(1

只等公子 2025-01-16 13:27:56

事实上,错误 (croak) 是在 try-catch-finally 的末尾报告的,而不是在调用有问题的代码的地方报告的似乎是由于 Try::Tiny 与名称空间的混淆所致;请参阅这篇文章中的讨论和评论。在复杂的 尝试子。一个简单的演示

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

打印

In try: ouch from a sub in main at try_tiny_mixup.pl line 14.
clean up

But the croak-ing sub is called at line 11 so that should be reports, not line 14.

更改 croak to die 使其打印 line 8 (这当然不是解决方案),同时使用 eval 而不是 Try::Tiny 结果正确第 11 行 已打印(什么是有效的解决方案)。请参阅链接的帖子。我不知道 Try::Tiny 是否有修复,但有直接替代品,请参见下文。

我不认为这以任何方式取决于执行的测试(正如我们所知,这里涉及数据库事务)。如果没有可运行的示例,我无法更具体地检查。

完全有效的一件事是恢复到 eval自 5.14 起 不再带有 Try::Tiny 所声明的原因的微妙之处。 Like

eval {
    this_croaks();
};
if ($@) { 
    print "In eval: $@";
}
say "clean up";

This 仍然过时,但它的工作原理就像预期的那样(并且 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)

(pragma experimental 替换了实验功能所需的两个语句。)

这正确地将其固定为第 12 行(来自第 9 行)的调用。请注意,还没有 finally 关键字。模块 Syntax::Keyword::Tiny (参见脚注)确实有它,因此可以使用它作为 Try::Tiny 的直接替代品。

我怀疑清除这个问题也会清除测试的行为。 (但我没有测试这一点。)


匿名子句的语法辅助(“糖”)(在很多方面并不那么幼稚)

已提交错误报告

§ 这是从 Syntax::Keyword::Try 由作者自己编写,因此您可能想尝试一下 - 但最好使用 功能::兼容::尝试,他们说。请参阅两者的文档,并查看其跟踪器

当我们进行实验时,请参阅 perlexperiment

The fact that the error (croak) is reported at the end of try-catch-finally blocks instead of where the offending code is called seems due to Try::Tiny's mixup with namespaces; see a discussion in this post and comments. The exact source of this misbehavior isn't clear to me in the complex try sub. A simple demo

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

This prints

In try: ouch from a sub in main at try_tiny_mixup.pl line 14.
clean up

But the croak-ing sub is called at line 11 so that should be reported, not line 14.

Changing croak to die makes it print line 8 (what of course isn't a solution) while using eval instead of Try::Tiny results in the correct line 11 printed (what is a valid solution). See the linked post. I am not aware of a fix with Try::Tiny but there are drop-in replacements, see below.

I don't see that this in any way depends on what tests are performed (here involving a database transaction as we are told). And I cannot check more specifically without a runable example.

The one thing that works fully is to revert to eval, which since 5.14 isn't anymore borne with subtleties that were the stated reason for Try::Tiny. Like

eval {
    this_croaks();
};
if ($@) { 
    print "In eval: $@";
}
say "clean up";

This is still archaic but it works just as intended (and Try::Tiny comes with twists of its own).

Hopefully the coming native try/catch, introduced as experimental in 5.34.0, won't have problems like this.§ For now it doesn't

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 replaces the two statements needed for experimental features.)

This correctly pegs it as called at line 12 (and coming from line 9). Note that there is no finally keyword yet. The module Syntax::Keyword::Tiny (see footnote) does have it so it may be possible to use it as a drop-in replacement for Try::Tiny.

I suspect that clearing this up will clear up the test's behavior as well. (But I didn't get to test that.)


Syntax aids ("sugar") for anonymous subs (which in many ways aren't so naive)

Submitted a bug report

§ This is getting ported from Syntax::Keyword::Try by the author themselves so you may want to try that -- but then better use Feature::Compat::Try, they say. See docs of both, and see its tracker.

Once we are at experimental stuff see perlexperiment.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文