鉴于以下角色:
package MyRole;
use Moo::Role;
sub foo {
return 'blah';
}
以下消费类:
package MyClass;
use Moo;
with 'MyRole';
around foo = sub {
my ($orig, $self) = @_;
return 'bak' if $self->$orig eq 'baz';
return $self->$orig;
}
我想测试around
修饰符中定义的行为。我该怎么做呢? Test :: MockModule似乎无法工作:
use MyClass;
use Test::Most;
use Test::MockModule;
my $mock = Test::MockModule->new('MyRole');
$mock->mock('foo' => sub { return 'baz' });
my $obj = MyClass->new;
# Does not work
is $obj->foo, 'bak', 'Foo is what it oughtta be';
编辑:我想要测试的是MyClass与MyRole的交互,如around
修饰符中所定义。我想测试around
修饰符中的代码是否符合我的想法。这是另一个与我的实际代码更接近的例子:
package MyRole2
use Moo::Role;
sub call {
my $self = shift;
# Connect to server, retrieve a document
my $document = $self->get_document;
return $document;
}
package MyClass2;
use Moo;
with 'MyRole2';
around call = sub {
my ($orig, $self) = @_;
my $document = $self->$orig;
if (has_error($document)) {
die 'Error';
}
return parse($document);
};
所以我想在这里做的是模拟MyRole2::call
以返回一个静态文档,该文档在我的测试装置中定义,包含错误并测试异常是否被正确抛出。我知道如何使用Test::More::throws_ok
或类似方法对其进行测试。我不知道该怎么做是模拟 MyRole2 :: call 和不 MyClass2::call
。
答案 0 :(得分:1)
来自#moose上的mst:
datetime
诀窍是在之前覆盖MyRole :: foo 任何使用它的东西都会被加载。这意味着使用use 5.016;
use Test::Most tests => 1;
require MyRole;
our $orig = MyRole->can('foo');
no warnings 'redefine';
*MyRole::foo = sub { goto &$orig };
{
local $orig = sub {'baz'};
require MyClass;
my $obj = MyClass->new;
is $obj->foo, 'bak', 'Foo is what it oughtta be';
}
代替require MyClass
,因为use MyClass
会转换为use MyClass
,它会在之前覆盖之前的所有内容,而加载。
答案 1 :(得分:0)
可以使用Test::MockModule
这些是所需的微小变化:
around foo {
应写为around foo => sub {
,因为around
需要子程序参考。
$self->$orig
需要写为$self->($orig)
文档将其列为my ($orig, $self) = @_;
,因此我将其更改为$orig->($self);
这是一个工作版本:
<强> MyRole.pm 强>
package MyRole;
use Moo::Role;
sub foo {
return 'foo blah';
}
sub bar {
return 'bar blah';
}
1;
<强> MyClass.pm 强>
package MyClass;
use Moo;
with 'MyRole';
around foo => sub {
my ($orig, $self) = (@_);
my ($result) = $orig->($self);
return 'bak' if $result eq 'baz'; # Will never return 'bak' as coded.
return $result;
};
<强> test.t 强>
#!/usr/bin/env perl
use MyClass;
use Test::Most;
use Test::MockModule;
my $obj = MyClass->new;
# foo has an around block, bar does not
is($obj->bar, 'bar blah', 'bar() returns [ bar blah ]');
is($obj->foo, 'foo blah', 'foo() returns [ foo blah ]');
my $mock = Test::MockModule->new('MyClass');
$mock->mock('foo' => sub { return 'mocked foo blah' } );
my $mocked = MyClass->new;
is($mocked->bar, 'bar blah', 'bar() still returns [ bar blah ]');
is($mocked->foo, 'mocked foo blah', 'foo() now returns mocked answer [ mocked foo blah ]');
运行
prove -v test.t
test.t ..
ok 1 - bar() returns [ bar blah ]
ok 2 - foo() returns [ foo blah ]
ok 3 - bar() still returns [ bar blah ]
ok 4 - foo() now returns mocked answer [ mocked foo blah ]
1..4
ok
All tests successful.
Files=1, Tests=4, 0 wallclock secs ( 0.06 usr 0.01 sys + 0.19 cusr 0.00 csys = 0.26 CPU)
Result: PASS
请看一下: