【问题标题】:Argument #1 must be of type Model, Pest\Mock\Mock given参数 #1 必须是 Model 类型,Pest\Mock\Mock 给定
【发布时间】:2021-12-14 12:55:27
【问题描述】:

我正在尝试使用 Pest 编写一些测试并模拟我的模型。 我有一个接受两个模型的存储库,这是定义:

class MyRepo
{
    public function __construct(private ModelA $modelA, private ModelB $modelB)
    {
      //
    }
}

现在在我的测试中,我为ModelAModelB 创建了两个模拟,并创建了存储库:

$modelA = mock(ModelA::class);
$modelB = mock(ModelB::class);

$repo = new MyRepo($modelA, $modelB);

运行此代码,我收到如下检查错误:

__construct(): Argument #1 ($modelA) must be of type App\Models\ModelA, Pest\Mock\Mock given

如果我删除 Repository 构造函数的类型检查,一切正常。

我试图找到解决方案,但目前我没有运气。我无法理解我需要进行哪些更改才能使其正常工作

【问题讨论】:

  • 你为什么要嘲笑模特?它真的是 Laravel 模型吗?如果是这样,你永远不要模拟 Laravel 的模型,而是使用 Factories

标签: laravel phpunit php-8 php-pest


【解决方案1】:

正如评论所述,不要模拟模型,这不是Laravel 中测试工具的预期用途。换句话说,我已经编写了数千个测试,而不必模拟模型一次。

将模型作为构造函数的参数是没有意义的。由于Laravels 容器通常只会将它们解析为空模型,resolve(MyRepo::class); 并且容器是 Mocking 的重要工具。

话虽如此,您面临的问题是,mock() 返回 Pest Mock 对象而不是 Mockery 对象,该对象位于 Pest Mock Class 上。这只能由calling expect() 返回。因此使用expect(),你需要在你的模拟上调用这些操作,你的代码应该可以工作。

mock(ModelA::class)
    ->shouldReceive('update')
    ->once()
    ->andReturn(true);

【讨论】:

  • 谢谢,对不起,但我是模拟对象的新手,我有点困惑。 “将模型作为构造函数的参数,没有意义”是什么意思?我在构造函数上有这两个模型,因为它是存储库,在我的应用程序中我从不创建这些模型,我使用 DI。错了吗?
  • 没错,我担心你想将具体模型注入到构造函数中。就像 new YourRepo(ModelA::find(1), ModelB::find(2)); 一样,这是不正确的,但如果你使用 DI,那是完全正确的。人们在模拟和测试中经常遇到困难,由于显示的代码,我在这里也这么认为。但你是完全正确的伙伴。
【解决方案2】:

现在查看您的答案,我使用工厂更改了代码,并将该工厂传递给存储库。这是正确的方法吗?

getUser 是我想要测试的方法,所以我用工厂创建了两个模型。对吗?

// prepare
$modelA = ModelA::factory()->create();
$modelB = ModelB::factory()->create();

$repository = new MyRepo($modelA, $modelB);
$service = new MyService($repository);

// act
$user = $service->getUser("fake");

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2019-03-04
    • 2020-01-06
    • 2021-05-12
    • 2017-12-17
    • 2021-09-27
    • 2023-02-14
    • 2022-08-21
    • 1970-01-01
    相关资源
    最近更新 更多