如何在 laravel 5 中模拟模型上的 create 方法?

Posted

技术标签:

【中文标题】如何在 laravel 5 中模拟模型上的 create 方法?【英文标题】:How can I mock the create method on a model in laravel 5? 【发布时间】:2015-12-14 21:32:30 【问题描述】:

我正在为我的 laravel 5 应用程序编写单元测试。在一个测试中,我调用了一个函数,并且需要验证它是否在被测函数中调用了另一个模型的静态 create 方法。

我不想真正将任何资源持久化到数据库中。

我创建了一个模拟对象,指定了期望,并将其绑定到应用程序实例,但是当调用 create 时,应用程序会尝试运行 SQL,而不是让模拟对象拦截函数调用。

public function testLogCreation() 
  $this->log = Mockery::mock('App\Models\Log');
  $this->log->shouldReceive('create')->once();
  $this->app->instance('App\Models\Log',$this->log);

  echo get_class($this->app['App\Models\Log']); // output: Mockery_2_App_Models_Log

有 1 个错误

SQLSTATE[23503]:外键违规:7 错误:在表“日志”上插入或更新违反外键约束....

我也尝试了$this->log->shouldReceive('save')->once();,因为我观察到静态create 函数调用公共save 函数,但我认为我没有在log 的正确实例上创建模拟期望。

如果这不能完成,有什么替代策略的建议吗?

谢谢!

【问题讨论】:

【参考方案1】:

众所周知,静态方法在单元测试中难以应对。线

$this->app->instance('App\Models\Log', $this->log);

在应用程序中安装你的 mock 以进行依赖注入,但依赖注入只对 Laravel 创建的对象起作用。静态方法实际上一个底层对象,所以它不适用。

您可以使用的一种方法是具有createLog 方法的工厂或服务接口。然后这个接口有一个具体的类,它使用静态方法创建日志模型(或者更好的是,不需要静态方法)。然后,您可以轻松地在测试中模拟该接口并验证是否调用了 createLog

查看此处以获得类似问题的最佳答案:Laravel Dependency Injection: When do you have to? When can you mock Facades? Advantages of either method?

【讨论】:

【参考方案2】:

您可以通过服务容器实例化一个 Eloquent 模型并在您的生产代码中对其运行 save() 来解决此问题(而不是使用 create() 方法)。

$log = $this->app->make('App\Models\Log')->fill($array);
$log->save();

这允许您模拟实际对象而不是外观或静态方法。然后你可以像在你的例子中一样使用 Mockery,只模拟 'fill' 和 'save' 方法。

【讨论】:

以上是关于如何在 laravel 5 中模拟模型上的 create 方法?的主要内容,如果未能解决你的问题,请参考以下文章

用于 PHPunit 的 Laravel 5.4 模型模拟

在 PHPUnit 中调用路由时如何在 Laravel 8 中模拟 Eloquent 模型

如何模拟 Laravel Eloquent 模型的静态方法?

Laravel 5.5 模型上的自定义软删除

在 Laravel 中模拟具有关系的模型

在 Laravel 中模拟具有关系的模型