如何告知Perl的Devel::Cover某个Readonly值永远不会为假?
问题描述
我有一个Perl模块,其中定义了一个Readonly常量作为默认值,当调用方未指定对应参数时就会使用该默认值,模块代码如下:
package Mcve; use strict; use warnings; use Readonly; Readonly our $CONST => 123; sub new { my ($class, %args) = @_; my $self = bless{}, $class; # uncoverable condition right # uncoverable condition false # uncoverable branch false $self->{'CONST'} = $args{'CONST'} || $CONST; return $self; }
对应的测试用例如下:
use strict; use warnings; use base 'Test::Class'; use Test::More; use Mcve; __PACKAGE__->runtests() unless caller; sub uses_default_arg: Test { my $mcve = Mcve->new(); is($mcve->{'CONST'}, 123); } sub overrides_default_arg: Test { my $mcve = Mcve->new('CONST' => 456); is($mcve->{'CONST'}, 456); }
我使用Devel::Cover收集测试覆盖率时,工具无法识别上述Readonly常量永远为真值,因此逻辑或表达式“两个值均为假”的条件永远不可能被覆盖。我已按照官方文档说明添加了# uncoverable ...系列注释(见上述模块代码),但覆盖率报告仍然显示条件覆盖率仅为66.6%,执行覆盖率统计的命令及输出如下:
~$ HARNESS_PERL_SWITCHES=-MDevel::Cover prove -Ilib t/ && cover ... ----------- ------ ------ ------ ------ ------ ------ ------ File stmt bran cond sub pod time total ----------- ------ ------ ------ ------ ------ ------ ------ lib/Mcve.pm 100.0 n/a 66.6 100.0 0.0 0.5 90.4 t/mcve.t 100.0 n/a n/a 100.0 n/a 99.4 100.0 Total 100.0 n/a 66.6 100.0 0.0 100.0 96.3 ----------- ------ ------ ------ ------ ------ ------ ------
HTML格式的覆盖率报告显示,Devel::Cover判定“两个值均为假”的分支未被覆盖:
当前运行环境:Perl 5.34,Devel::Cover 1.36。请问要如何设置才能告知Devel::Cover该条件属于不可覆盖分支?
解决方法
之前添加的注释不生效,核心原因是Devel::Cover对uncoverable注释的匹配规则要求注释必须精准对应代码行的条件序号、判定结果,不会自动合并多行注释的规则。针对$a || $b这类短路或运算符,一共存在3个可统计的条件组合:
- 左侧操作数为真
- 左侧操作数为假、右侧操作数为真
- 左右操作数均为假(即当前无法覆盖的场景)
可选择以下任意一种方案解决:
- 精准标注不可覆盖条件
删掉原来的三行注释,在逻辑表达式的上一行添加精准匹配的注释即可:# uncoverable condition 3 false $self->{'CONST'} = $args{'CONST'} || $CONST; - 重构代码从根源消除不可达条件(推荐)
原来的||写法本身存在逻辑隐患:如果调用方传入的合法参数是假值(比如0、空字符串),会被错误判定为需要使用默认值。改成显式的exists检查既能修复逻辑问题,又只会产生两个可覆盖的分支,现有测试用例即可实现100%覆盖率,不需要加任何特殊注释:$self->{'CONST'} = exists $args{'CONST'} ? $args{'CONST'} : $CONST; - 命令行手动忽略指定条件
运行cover命令时追加参数,指定忽略对应行的未覆盖条件即可,注意把行号替换为本地代码中赋值语句的实际行号:cover -ignore_re 'lib/Mcve.pm: cond 3,line 14'
内容的提问来源于stack exchange,提问作者Robert
相关产品推荐
相关产品推荐

