You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Perl脚本mkpath错误场景无物理修改单元测试方案及代码疑问

关于Perl mkpath单元测试的注意事项与改进方案

嘿,咱们来聊聊你这段测试代码的问题和优化方向吧!你想用Mock来模拟文件系统错误,这个思路完全正确,但当前代码还有不少可以调整的地方,让测试更可靠、更脱离真实环境的依赖:

核心注意事项

1. 不要依赖真实文件系统

你当前的Override逻辑是把$dir改成/baddir,然后调用真实的File::Path::mkpath——这本质上还是在碰真实的文件系统,如果/baddir碰巧能被创建(比如测试机器上你有root权限),这个测试就失效了。Mock的核心就是完全脱离真实环境,直接让mkpath抛出你想要的错误,而不是靠修改路径去碰运气。

2. 全局变量限制了测试灵活性

你的$my_dir是全局变量,testme直接引用它,这意味着每次测试只能针对同一个目录。最好把$my_dir作为参数传给testme,这样你可以轻松测试不同的路径场景(比如带子目录的路径、非法字符的路径等)。

3. 缺少自动化断言

你现在只是打印结果,没有用Test::More的断言(比如like、is)来验证错误信息是否符合预期。手动看输出没法实现自动化测试,必须用断言让测试框架自动判断结果是否正确。

4. 不要在Mock里调用真实函数

原代码中你的Override子函数又调用了File::Path::mkpath,这完全违背了Mock的初衷——我们就是要替换掉真实的函数,模拟错误,而不是转发调用。

改进后的示例代码

下面是调整后的测试代码,解决了上面的问题,同时覆盖了多种错误场景:

use warnings;
use strict;
use Test::More tests => 4; # 声明测试总数
use Sub::Override;
use File::Path qw{ mkpath };

# 重构testme,接收目录参数,逻辑更清晰
sub testme {
    my ($target_dir) = @_;
    my $err_msg = "";

    eval {
        mkpath($target_dir, 0, 0777);
    };

    if ($@) {
        $err_msg = "Could not create directory $target_dir. Error was as follows: $@\n";
    }

    return $err_msg;
}

# 测试场景1:模拟权限不足错误
{
    my $override = Sub::Override->new(
        'mkpath' => sub {
            my ($dir) = @_;
            # 直接抛出模拟的错误,完全不依赖真实文件系统
            die "Permission denied: '$dir'";
        }
    );

    my $result = testme("restricted_dir");
    like($result, qr/Could not create directory restricted_dir/, "Error message includes target directory");
    like($result, qr/Permission denied/, "Error message captures permission error");
}

# 测试场景2:模拟父目录不存在且无法创建的错误
{
    my $override = Sub::Override->new(
        'mkpath' => sub {
            die "No such file or directory: 'nonexistent_parent/child'";
        }
    );

    my $result = testme("nonexistent_parent/child");
    like($result, qr/No such file or directory/, "Captures missing parent directory error");
}

# 测试场景3:模拟磁盘已满错误
{
    my $override = Sub::Override->new(
        'mkpath' => sub {
            die "No space left on device";
        }
    );

    my $result = testme("dir_on_full_disk");
    like($result, qr/No space left on device/, "Captures disk full error");
}

额外优化建议

  • 模拟真实错误格式:尽量让Mock抛出的错误信息和真实mkpath的错误格式一致,这样你的错误处理逻辑才能得到更真实的测试。比如原版mkpath的错误通常会包含具体路径,你的模拟die也要带上路径。
  • 试试Test::Exception:如果你觉得手动处理eval和$@麻烦,可以用Test::Exception模块,它提供了dies_ok、throws_ok等断言,能更简洁地测试异常场景:
    use Test::Exception;
    
    {
        my $override = Sub::Override->new('mkpath' => sub { die "Permission denied" });
        throws_ok { mkpath("locked_dir", 0, 0777) } qr/Permission denied/, "mkpath dies with expected error";
    }
    
  • 隔离测试用例:用块级作用域包裹每个Sub::Override,确保每个测试用例的Mock是独立的,不会互相干扰——这一点你原代码做得很好,继续保持!

内容的提问来源于stack exchange,提问作者paulj

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.15 07:44:07