perl 中的单元测试,接收散列引用为 return 预期 return 来自散列中的键的字符串
Unit testing in perl, Receiving hash ref as return expected to return a string from a key in a hash
我正在尝试测试以下方法的输出:
package ASC::Builder::Error;
sub new {
my ($package, $first_param) = (shift, shift);
if (ref $first_param eq 'HASH') {
my %params = @_;
return bless { message => $first_param->{message}, %params}, $package;
}
else {
my %params = @_;
return bless {message => $first_param, %params}, $package;
}
}
此方法应该接受错误散列或错误字符串。如果它接受一个散列,它应该从错误散列中输出消息键的值。
这是位于 ErrorLibrary.pm 中的错误散列:
use constant {
CABLING_ERROR => {
code => 561,
message => "cabling is not correct at T1",
tt => { template => 'disabled'},
fatal => 1,
link =>'http://www.e-solution.com/CABLING_ERROR',
},
};
这是消息方法以及位于 Error.pm
中的散列的其他键
package ASC::Builder::Error;
sub message {
return $_[0]->{message};
}
sub tt {
return {$_[0]->{tt} };
}
sub code {
return {$_[0]->{code} };
}
这是我当前位于 error.t
的单元测试
#input value will either be a String or and Error Message Hash
# error hash
my $error_hash = CABLING_ERROR;
# error string
my $error_string = "cabling is not correct at T1.";
# error hash is passed into new and an error object is outputted
my $error_in = ASC::Builder::Error->new($error_hash);
# checks to see if the output object from new is an Error object
isa_ok($error_in, 'ASC::Builder::Error');
# checking that object can call the message() method
can_ok( $error_in, 'message');
# checks to see if the output message matches the message contained in the error hash(correct)
is($error_in->message(),( $error_string || $error_hash->{message} ), 'Returns correct error message');
最后是我的测试结果:
# Failed test 'Returns correct error message'
# at t/67_error_post.t line 104.
# got: 'HASH(0x38b393d490)'
# expected: 'cabling is not correct at T1.'
#
# '
# Looks like you failed 1 test of 3.
t/67_error_post.t .. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/3 subtests
在我的机器上
首先,如果我 运行 你的代码,我会收到关于 CABLING_CHECK_TOR_INCORRECT_CABLING_ERROR
未定义的错误。如果我将其替换为 CABLING_ERROR
,测试将失败。
# got: 'cabling is not correct at T1'
# expected: 'cabling is not correct at T1.'
# Looks like you failed 1 test of 3.
同时有两个可能的输出
现在按照你所说的输出。
出于某种原因,您的 $error_in->message
return 是一个 hashref,它被 is()
字符串化,因为 is()
不做数据结构。您可以使用 Test::Deep 来执行此操作。
use Test::Deep;
cmp_deeply(
$error_in->message,
any(
$error_string,
$error_hash->{message},
),
'Returns correct error message',
);
这里我假设你的 $error_string || $error_hash->{message}
是为了让它检查其中之一。
但是 ||
只会检查 $error_string
是否有真值和 return 它,或者取 $error_hash->{message}
的值。它将该操作的结果与 $error_in->message
.
进行比较
测试清楚
但是,这可能无法解决您的实际问题。不要用一个测试用例来检查两种可能的事情,而是为每个可能的输入制作一个 专用测试用例 。这就是单元测试的意义所在。
my $error_direct = ASC::Builder::Error->new('foo');
is $error_direct->message, 'foo', 'direct error message gets read correctly';
my $error_indirect = ASC::Builder::Error->new( { message => 'bar' } );
is $error_indirect->message, 'bar', 'indirect error message gets read correctly';
上面的代码会给你两个测试用例。一个用于 direct 错误字符串,另一个用于 indirect 哈希。
ok 1 - direct error message gets read correctly
ok 2 - indirect error message gets read correctly
1..2
不要浪费时间
同时,这也解决了您方法的另一个问题。在单元测试中,您想测试 尽可能小的单元 。不要将它们与您的其他业务逻辑或业务生产数据联系起来。
你的 ASC::Builder::Error
class 不关心错误的类型,所以不要通过加载额外的东西来为你提供与现实生活中完全相同的错误消息而过于复杂.只需使用足以证明东西有效的简单东西。
你的单元测试越简单,就越容易维护,一旦你有更多的案例,就越容易添加。
我正在尝试测试以下方法的输出:
package ASC::Builder::Error;
sub new {
my ($package, $first_param) = (shift, shift);
if (ref $first_param eq 'HASH') {
my %params = @_;
return bless { message => $first_param->{message}, %params}, $package;
}
else {
my %params = @_;
return bless {message => $first_param, %params}, $package;
}
}
此方法应该接受错误散列或错误字符串。如果它接受一个散列,它应该从错误散列中输出消息键的值。
这是位于 ErrorLibrary.pm 中的错误散列:
use constant {
CABLING_ERROR => {
code => 561,
message => "cabling is not correct at T1",
tt => { template => 'disabled'},
fatal => 1,
link =>'http://www.e-solution.com/CABLING_ERROR',
},
};
这是消息方法以及位于 Error.pm
中的散列的其他键package ASC::Builder::Error;
sub message {
return $_[0]->{message};
}
sub tt {
return {$_[0]->{tt} };
}
sub code {
return {$_[0]->{code} };
}
这是我当前位于 error.t
的单元测试#input value will either be a String or and Error Message Hash
# error hash
my $error_hash = CABLING_ERROR;
# error string
my $error_string = "cabling is not correct at T1.";
# error hash is passed into new and an error object is outputted
my $error_in = ASC::Builder::Error->new($error_hash);
# checks to see if the output object from new is an Error object
isa_ok($error_in, 'ASC::Builder::Error');
# checking that object can call the message() method
can_ok( $error_in, 'message');
# checks to see if the output message matches the message contained in the error hash(correct)
is($error_in->message(),( $error_string || $error_hash->{message} ), 'Returns correct error message');
最后是我的测试结果:
# Failed test 'Returns correct error message'
# at t/67_error_post.t line 104.
# got: 'HASH(0x38b393d490)'
# expected: 'cabling is not correct at T1.'
#
# '
# Looks like you failed 1 test of 3.
t/67_error_post.t .. Dubious, test returned 1 (wstat 256, 0x100)
Failed 1/3 subtests
在我的机器上
首先,如果我 运行 你的代码,我会收到关于 CABLING_CHECK_TOR_INCORRECT_CABLING_ERROR
未定义的错误。如果我将其替换为 CABLING_ERROR
,测试将失败。
# got: 'cabling is not correct at T1'
# expected: 'cabling is not correct at T1.'
# Looks like you failed 1 test of 3.
同时有两个可能的输出
现在按照你所说的输出。
出于某种原因,您的 $error_in->message
return 是一个 hashref,它被 is()
字符串化,因为 is()
不做数据结构。您可以使用 Test::Deep 来执行此操作。
use Test::Deep;
cmp_deeply(
$error_in->message,
any(
$error_string,
$error_hash->{message},
),
'Returns correct error message',
);
这里我假设你的 $error_string || $error_hash->{message}
是为了让它检查其中之一。
但是 ||
只会检查 $error_string
是否有真值和 return 它,或者取 $error_hash->{message}
的值。它将该操作的结果与 $error_in->message
.
测试清楚
但是,这可能无法解决您的实际问题。不要用一个测试用例来检查两种可能的事情,而是为每个可能的输入制作一个 专用测试用例 。这就是单元测试的意义所在。
my $error_direct = ASC::Builder::Error->new('foo');
is $error_direct->message, 'foo', 'direct error message gets read correctly';
my $error_indirect = ASC::Builder::Error->new( { message => 'bar' } );
is $error_indirect->message, 'bar', 'indirect error message gets read correctly';
上面的代码会给你两个测试用例。一个用于 direct 错误字符串,另一个用于 indirect 哈希。
ok 1 - direct error message gets read correctly
ok 2 - indirect error message gets read correctly
1..2
不要浪费时间
同时,这也解决了您方法的另一个问题。在单元测试中,您想测试 尽可能小的单元 。不要将它们与您的其他业务逻辑或业务生产数据联系起来。
你的 ASC::Builder::Error
class 不关心错误的类型,所以不要通过加载额外的东西来为你提供与现实生活中完全相同的错误消息而过于复杂.只需使用足以证明东西有效的简单东西。
你的单元测试越简单,就越容易维护,一旦你有更多的案例,就越容易添加。