Hun*_*len 5 perl code-coverage
在工作单元测试中实现代码覆盖的悲伤状态后,我正在尝试创建一个实用程序,它将扫描我们的代码库并标记没有100%的文件.我找到了两种获得所有方法的方法:
直接访问符号表:
for my $classname ( @ARGV ) {
eval "require $classname";
die "Can't load $classname $EVAL_ERROR"
if $EVAL_ERROR;
no strict 'refs';
METHODS:
for my $sym ( keys %{ "${classname}::" } ) {
next METHODS unless defined &{"${classname}::${sym}"};
print "$sym\n";
}
}
Run Code Online (Sandbox Code Playgroud)
使用Class::InspectorCPAN中的模块:
for my $classname ( @ARGV ) {
my @methods = Class::Inspector->methods($classname, 'public');
print Dumper \@methods;
}
Run Code Online (Sandbox Code Playgroud)
这两种方法产生了类似的结果; 这些问题是它们显示了整个模块可用的所有方法,而不仅仅是该模块内部定义的方法.
有没有办法区分模块可访问的方法和模块内部明确定义的方法?
注意:我没有尝试创建完整的代码覆盖率测试,对于我的用例,我只想测试所有方法至少被调用过一次.完整的覆盖测试Devel::Cover对我们来说太过分了.
每个子(或更具体地说,每个 CV)都会记住它最初在哪个包中声明。测试用例:
Foo.pm:
package Foo;
sub import {
*{caller . "::foo"} = sub{};
}
1;
Run Code Online (Sandbox Code Playgroud)
Bar.pm:
package Bar;
use Foo;
our $bar; # introduces *Bar::bar which does not have a CODE slot
sub baz {}
1;
Run Code Online (Sandbox Code Playgroud)
现在访问符号表会给出foo和baz。顺便说一句,我会这样编写代码(原因很快就会清楚):
my $classname = 'Bar';
for my $glob (values %{ "${classname}::" }) {
my $sub = *$glob{CODE} or next;
say *$glob{NAME};
}
Run Code Online (Sandbox Code Playgroud)
接下来,我们要深入B模块来反思底层的C数据结构。我们用B::svref_2object函数来做到这一点。这将生成一个B::CV具有方便STASH字段的对象(它返回一个B::HV具有NAME字段的对象):
use B ();
my $classname = 'Bar';
for my $glob (values %{ "${classname}::" }) {
my $sub = *$glob{CODE} or next;
my $cv = B::svref_2object($sub);
$cv->STASH->NAME eq $classname or next;
say *$glob{NAME};
}
Run Code Online (Sandbox Code Playgroud)
添加一些健全性检查,这应该效果很好。
动态类/模块加载不应通过 string 完成eval。相反,我建议Module::Runtime:
Module::Runtime::require_module($classname);
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
160 次 |
| 最近记录: |