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

Laravel 5.5中如何测试内部创建对象的方法调用情况?

在Laravel 5.5中测试类内部对象的方法调用

嗨,针对你的需求,要验证调用A::createQuery($variable)时B类的指定方法是否被调用,我们可以借助Laravel默认集成的Mockery工具来实现。核心思路是通过模拟B类的实例,替换掉A类中直接创建的真实B对象,从而跟踪方法的调用情况。下面是具体的实现步骤:

1. 调整A类的结构(提升可测试性)

原代码中A::createQuery直接new B(),导致我们无法替换成模拟对象。我们可以提取一个创建B实例的工厂方法,这样在测试时就能轻松替换它的返回值:

class A {
    // 新增受保护的工厂方法,用于创建B实例
    protected static function createB($variable) {
        return new B($variable);
    }

    public static function createQuery($variable){
        $b = static::createB($variable); // 改用工厂方法创建实例
        if($variable === 1){
            $b->withShoes();
        }
        if($variable === 2){
            $b->withSocks();
        }
        if($variable === 1 || $variable === 3){
            $b->withFriends();
        }
        return $b->get();
    }
}

这个改动很小,但能大幅提升代码的可测试性,同时不影响原有功能。

2. 编写测试用例

接下来我们编写测试类,验证不同$variable值下B类方法的调用情况:

use Mockery;
use Tests\TestCase;

class ATest extends TestCase
{
    /**
     * 测试当$variable=1时,withShoes和withFriends被调用
     */
    public function testCreateQueryCallsWithShoesAndFriendsWhenVariableIs1()
    {
        // 1. 创建B类的模拟对象
        $mockB = Mockery::mock(B::class);
        
        // 2. 设置预期:withShoes方法被调用1次,链式调用需返回自身
        $mockB->shouldReceive('withShoes')
            ->once()
            ->andReturnSelf();
        
        // 3. 设置预期:withFriends方法被调用1次
        $mockB->shouldReceive('withFriends')
            ->once()
            ->andReturnSelf();
            
        // 4. 设置预期:get方法被调用1次,并返回测试用结果
        $mockB->shouldReceive('get')
            ->once()
            ->andReturn('test-result');

        // 5. 替换A类的createB方法,返回我们的模拟对象
        $this->mock(A::class, function ($mock) use ($mockB) {
            $mock->shouldReceive('createB')
                ->with(1)
                ->andReturn($mockB);
        });

        // 6. 调用待测试的方法
        $result = A::createQuery(1);

        // 7. 验证返回结果(可选,根据需求添加)
        $this->assertEquals('test-result', $result);
    }

    /**
     * 测试当$variable=2时,withShoes不会被调用
     */
    public function testCreateQueryDoesNotCallWithShoesWhenVariableIs2()
    {
        $mockB = Mockery::mock(B::class);
        
        // 设置预期:withShoes永远不会被调用
        $mockB->shouldReceive('withShoes')
            ->never();
            
        // 设置预期:withSocks被调用1次
        $mockB->shouldReceive('withSocks')
            ->once()
            ->andReturnSelf();
            
        $mockB->shouldReceive('get')
            ->once()
            ->andReturn('test-result');

        $this->mock(A::class, function ($mock) use ($mockB) {
            $mock->shouldReceive('createB')
                ->with(2)
                ->andReturn($mockB);
        });

        A::createQuery(2);
    }

    // 测试结束后清理Mockery资源
    protected function tearDown(): void
    {
        parent::tearDown();
        Mockery::close();
    }
}

关键说明

  • Mockery核心作用:模拟B类的实例,我们可以精确指定某个方法是否被调用、调用次数、传入参数等。如果实际调用不符合预期,测试会直接失败。
  • 工厂方法的意义:通过提取createB方法,我们避免了在测试中修改A类的核心逻辑,同时实现了对B实例的替换。
  • 链式调用处理:因为B类的方法是链式调用(比如$b->withShoes()->get()),所以我们需要在模拟时用andReturnSelf()来维持链式结构。

运行测试后,如果方法调用不符合预期,Mockery会抛出明确的错误提示,帮助你快速定位问题。

内容的提问来源于stack exchange,提问作者Z.S

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.11 08:59:53