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

使用RefreshDatabase Trait时出现Could not load mock: class already exists错误

问题描述

测试代码如下:

public function testSomething()
{
    $this->login();

    m::mock('overload:MyClass', function ($mock) {
        $mock->shouldReceive('METHOD')
            ->andReturn(
                (object)[
                    'status'  => true,
                    'message' => 'Message',
                ]
            );
    });

    $this->post(route('ROUTE'))
        ->assertRedirect()
        ->assertSessionHas(
            'success',
            'Message'
        );
}

运行测试时出现以下差异:

  • 使用 use DatabaseTransactions:测试正常执行
  • 使用 use RefreshDatabase:测试失败,报错信息:
    Mockery\Exception\RuntimeException : Could not load mock \MyClass, class already exists
    

环境版本:

  • Laravel 5.5
  • PHPUnit 6.5.14

已尝试方案:

  • 在测试类添加 @runTestsInSeparateProcesses 注解
  • 在单个测试方法添加 @runInSeparateProcess 注解

问题原因

RefreshDatabase 特性会在测试启动阶段就执行数据库迁移操作,这个过程中可能已经触发了 MyClass 的自动加载。而 Mockery 的 overload: 语法要求必须在类被加载前创建 mock,否则就会抛出「类已存在」的错误。

反观 DatabaseTransactions,它是在测试方法执行阶段才启动数据库事务,mock 创建的时机早于 MyClass 的加载,因此可以正常工作。


解决方案

方案1:调整 Mock 创建时机,提前到类加载前

在测试类的 setUp 方法中,先创建 mock,再执行父类的 setUp(即 RefreshDatabase 的迁移逻辑):

protected function setUp()
{
    // 先创建mock,确保MyClass还没被加载
    m::mock('overload:MyClass', function ($mock) {
        $mock->shouldReceive('METHOD')
            ->andReturn(
                (object)[
                    'status'  => true,
                    'message' => 'Message',
                ]
            );
    });

    parent::setUp();
}

之后测试方法中无需重复编写 mock 代码。

方案2:利用 Laravel 容器替换实例(更推荐)

放弃 Mockery 的 overload: 语法,改用 Laravel 容器绑定注入 mock 实例,这种方式不受类是否已加载的限制:

public function testSomething()
{
    $this->login();

    // 创建MyClass的mock
    $mock = m::mock(MyClass::class);
    $mock->shouldReceive('METHOD')
        ->andReturn(
            (object)[
                'status'  => true,
                'message' => 'Message',
            ]
        );

    // 将mock绑定到容器,后续系统会从容器获取实例
    $this->app->instance(MyClass::class, $mock);

    $this->post(route('ROUTE'))
        ->assertRedirect()
        ->assertSessionHas(
            'success',
            'Message'
        );
}

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 04:45:42