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

如何用Test::Spec模拟get_dbh函数编写func_for_test单元测试?

解决Test::Spec中模拟get_dbh的问题

问题根源

你的ModuleForTests.pm在编译阶段就执行了my $dbh = get_dbh();,后续对get_dbh的mock根本影响不到已经初始化的$dbh变量,这就是之前尝试的方法全部失效的原因。

正确Mock方案

方案一:提前mock ModuleMysql模块

在加载ModuleForTests之前,先通过Test::MockModule替换ModuleMysql的get_dbh函数,让它返回我们的mock数据库句柄。

use Test::Spec;
use Test::MockModule;
use DBD::Mock;

# 先mock ModuleMysql,再加载目标模块
my $mock_mysql = Test::MockModule->new('ModuleMysql');
my $mock_dbh = DBI->connect('DBI:Mock:', '', '');
$mock_mysql->mock('get_dbh', sub { return $mock_dbh });

# 此时加载ModuleForTests,它会使用mock后的get_dbh赋值$dbh
use ModuleForTests;

describe "func_for_test" => sub {
    it "应执行DELETE语句" => sub {
        func_for_test();

        # 验证SQL执行记录
        my @statements = $mock_dbh->{mock_all_history};
        is(scalar @statements, 1, "执行了1条SQL语句");
        like($statements[0]->statement, qr/DELETE/, "SQL为DELETE语句");
    };
};

runtests unless caller;

方案二:直接修改ModuleForTests的$dbh变量

如果不想提前mock模块,可以直接通过符号表访问并修改ModuleForTests中已初始化的$dbh变量:

use Test::Spec;
use ModuleForTests;
use DBD::Mock;

describe "func_for_test" => sub {
    before each => sub {
        # 创建mock数据库句柄
        my $mock_dbh = DBI->connect('DBI:Mock:', '', '');
        # 修改ModuleForTests包中的$dbh变量
        no strict 'refs';
        ${'ModuleForTests::dbh'} = $mock_dbh;
    };

    it "应正确准备DELETE语句" => sub {
        func_for_test();
        no strict 'refs';
        my @history = ${'ModuleForTests::dbh'}->{mock_all_history};
        ok(grep { $_->statement =~ /DELETE/ } @history, "已执行DELETE语句");
    };
};

runtests unless caller;

之前方法失效的原因

  • 直接用DBD::Mock连接无效:get_dbh内部的DBI->connect调用和你单独创建的mock句柄无关,无法覆盖原有的数据库连接。
  • 直接stubs ModuleForTests->get_dbh无效:get_dbh是ModuleMysql的函数,且ModuleForTests在编译时已经将get_dbh的返回值存入$dbh,后续mock无法改变这个已初始化的变量。

内容的提问来源于stack exchange,提问作者Вета Хмелёва

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.26 07:03:15