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

PHPUnit测试报错:Mockery部分Mock调用executeActiveBlueprintRules方法不存在

解决Mockery Partial Mock调用真实方法时报错的问题

错误信息

Mockery\Exception\BadMethodCallException: Method Mockery_0__Tests_Unit_App_Utils_Blueprints_BlueprintRuleUtil::executeActiveBlueprintRules() does not exist on this mock object

问题原因

  1. 命名空间解析错误:测试类位于Tests\Unit命名空间下,创建mock时使用App\Utils\Blueprints\BlueprintRuleUtil::class会被解析为相对命名空间(Tests\Unit\App\Utils\Blueprints\BlueprintRuleUtil),而非根命名空间下的目标类。Mockery基于错误的类名生成mock,该类实际不存在,导致mock类未继承正确的被测类,因此没有executeActiveBlueprintRules方法。
  2. 静态调用绕开mock:被测类中存在静态方法调用(self::xxx、BlueprintRuleUtil::xxx),这类调用不会走mock实例,导致测试中mock的方法无法生效。

解决方案

1. 修正Mock创建的类名引用

测试类已通过use App\Utils\Blueprints\BlueprintRuleUtil;引入目标类,直接使用类名创建mock即可:

// 替换原mock创建代码
$blueprint_rule_util_partial_mock = \Mockery::mock(BlueprintRuleUtil::class)->makePartial();

或者使用完全限定名(前缀加反斜杠,确保解析为根命名空间类):

$blueprint_rule_util_partial_mock = \Mockery::mock(\App\Utils\Blueprints\BlueprintRuleUtil::class)->makePartial();

2. 将被测类中的静态调用改为实例调用

修改BlueprintRuleUtil类中的两处静态调用,确保方法调用走实例,让mock能拦截:

// 修改executeActiveBlueprintRules方法中的静态调用
// 原代码:
// BlueprintRuleUtil::addDefaultOutsourceCostToStrategy($strategy, $active_blueprint_rule);
// 修改为:
$this->addDefaultOutsourceCostToStrategy($strategy, $active_blueprint_rule);

// 修改addDefaultOutsourceCostToStrategy方法中的静态调用
// 原代码:
// if (self::shouldAddDefaultOutsourceCost($strategy)) {
// 修改为:
if ($this->shouldAddDefaultOutsourceCost($strategy)) {

修正后的测试方法代码片段

public function testExecuteActiveBlueprintRulesShouldExecuteDefaultOutsourceCostRule()
{
    Strategy::fake();

    Strategy::create(['id' => 1]);
    $createdStrategy = Strategy::getCreatedModel();

    // 使用正确的类名创建partial mock
    $blueprint_rule_util_partial_mock = \Mockery::mock(BlueprintRuleUtil::class)->makePartial();

    $active_blueprint_rule = new stdClass();
    $active_blueprint_rule->id = 1001;

    DB::shouldReceive("table")
        ->with('blueprint_rules')
        ->once()->andReturnSelf();

    DB::shouldReceive("where")
        ->with('is_active', true)
        ->andReturnSelf();

    DB::shouldReceive("get")
        ->andReturn([$active_blueprint_rule]);

    $blueprint_rule_util_partial_mock->shouldReceive('addDefaultOutsourceCostToStrategy')
        ->withAnyArgs();
    $blueprint_rule_util_partial_mock->shouldReceive('shouldAddDefaultOutsourceCost')->withAnyArgs()->andReturn(true);

    $blueprint_rule_util_partial_mock->executeActiveBlueprintRules($createdStrategy);

    Strategy::stopFaking();
}

修正后的被测类核心代码片段

class BlueprintRuleUtil
{
    const DEFAULT_OUTSOURCE_COST_RULE_ID = 1001;

    public function executeActiveBlueprintRules(Strategy $strategy)
    {
        if (!is_null($strategy)) {
            $active_blueprint_rules = DB::table('blueprint_rules')
                ->where('is_active', true)
                ->get();

            foreach ($active_blueprint_rules as $active_blueprint_rule) {
                if (!is_null($active_blueprint_rule) && $active_blueprint_rule->id === self::DEFAULT_OUTSOURCE_COST_RULE_ID) {
                    // 改为实例调用
                    $this->addDefaultOutsourceCostToStrategy($strategy, $active_blueprint_rule);
                }
            }
        }
    }

    public function addDefaultOutsourceCostToStrategy(Strategy $strategy, object $active_blueprint_rule)
    {
        // 改为实例调用
        if ($this->shouldAddDefaultOutsourceCost($strategy)) {
            $department_slug = 'data-intelligence';
            $department = DB::table('departments')
                ->where('slug', $department_slug)
                ->first();

            if (!is_null($department)) {
                $strategy_cost = new StrategyCost;
                $strategy_cost->name = 'Snowflake';
                $strategy_cost->department_id = $department->id;
                $strategy_cost->strategy_id = $strategy->id;
                $strategy_cost->month_1 = $active_blueprint_rule->amount;
                $strategy_cost->save();
                $strategy_cost->strategy->recalculate();
            } else {
                Log::debug("BlueprintRuleUtil: department $department_slug not found, did not add default outsource cost");
            }
        }
    }
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.06 02:45:32