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

如何正确Mock Laravel模型以测试关联用户创建业务逻辑

前置操作:修复业务代码拼写错误

你提供的业务代码存在2处变量大小写不一致的问题,会直接导致运行报错,请先修正:

  1. __invoke方法中,$this->updateUserUser2Id($user2->id); 修改为 $this->updateUserUser2Id($User2->id);
  2. updateUser2UsernameWithId方法中,参数声明为User2 $User2,方法体内所有$user2统一修改为$User2

测试实现方案

核心思路

  • 对于User对象,直接使用带属性预赋值的部分Mock即可,无需手动处理魔术方法__get的返回逻辑,避免属性访问报错
  • 对于User2的静态调用create,使用别名Mock实现静态方法的调用验证
  • 私有方法generateUser2Username的逻辑无需直接调用,通过断言User2::create接收的username参数即可间接验证逻辑正确性

完整测试代码

use App\User;
use App\Page\Actions\CreateUser2ForUserAction;
use App\Models\Shops\User2;
use Mockery;

class CreateUser2ForUserActionTest extends \Tests\TestCase
{
    public function test_action_executes_as_expected()
    {
        // 1. 构造测试基础数据
        $testUserName = 'Joe Bloggs';
        $testUserEmail = 'joe@example.com';
        $testUser2Id = 123;
        $expectedInitUsername = 'JoeBlo'; // generateUser2Username的预期输出
        $expectedFinalUsername = $expectedInitUsername . $testUser2Id;

        // 2. Mock User对象,预赋值属性,配置save方法期望
        $mockUser = Mockery::mock(User::class)->makePartial();
        $mockUser->name = $testUserName;
        $mockUser->email = $testUserEmail;
        $mockUser->shouldReceive('save')
            ->once()
            ->andReturn(true);

        // 3. Mock User2实例,配置属性和save方法期望
        $mockUser2Instance = Mockery::mock(User2::class)->makePartial();
        $mockUser2Instance->id = $testUser2Id;
        $mockUser2Instance->shouldReceive('save')
            ->once()
            ->andReturn(true);

        // 4. Mock User2静态create方法,验证入参
        Mockery::mock('alias:' . User2::class)
            ->shouldReceive('create')
            ->once()
            ->with([
                'username' => $expectedInitUsername,
                'email' => $testUserEmail,
                'user_type' => CreateUser2ForUserAction::A_USER_TYPE
            ])
            ->andReturn($mockUser2Instance);

        // 5. 执行业务逻辑
        $action = new CreateUser2ForUserAction();
        $resultUser = $action($mockUser);

        // 6. 后置断言
        // 验证User对象user2_id被正确赋值
        $this->assertEquals($testUser2Id, $resultUser->user2_id);
        // 验证User2对象最终username被正确修改
        $this->assertEquals($expectedFinalUsername, $mockUser2Instance->username);
    }

    protected function tearDown(): void
    {
        parent::tearDown();
        Mockery::close(); // 清理Mockery实例避免污染其他测试
    }
}

测试点覆盖说明

  • ✅ generateUser2Username逻辑验证:通过User2::create的入参username为预期的JoeBlo,间接验证私有方法逻辑正确
  • ✅ User2::create入参验证:Mock时指定with参数,不匹配会直接抛出测试失败
  • ✅ User2::save调用验证:Mock实例配置save方法调用次数期望
  • ✅ User::save调用验证:Mock User实例配置save方法调用次数期望
  • ✅ User.user2_id赋值验证:执行完成后直接断言User对象的user2_id属性等于Mock的User2ID

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.25 06:45:04