如何在 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 8 中模拟 Eloquent 模型