如何Mock Laravel模型关联?视图关联测试填充难题
解决Laravel中Feature测试Mock模型关联数据库视图的问题
方案一:直接用setRelation设置关联数据(推荐)
无需Mock工具,直接利用Eloquent内置的setRelation方法,给已创建的Town实例绑定模拟的TemperatureView数据,彻底绕过数据库视图查询。
示例测试代码:
public function test_town_show_displays_temperature() { // 创建真实的Town实例(可通过工厂快速生成) $town = Town::factory()->create(); // 构建模拟的TemperatureView实例,无需保存到数据库 $mockTempView = TemperatureView::make([ 'town_id' => $town->id, 'current_temp' => 28, // 填充视图所需的其他字段 ]); // 直接给Town实例设置关联结果 $town->setRelation('temperatureView', $mockTempView); // 发起请求 $response = $this->get(route('town.show', $town)); // 断言温度值存在于响应中 $response->assertSee('28'); }
原理:setRelation会直接覆盖模型的关联缓存,控制器中调用$town->temperatureView或load('temperatureView')时,会直接返回你预设的实例,不会触发数据库视图查询。
方案二:Mock模型实例的关联方法
如果需要模拟关联的查询过程,可以用Mockery针对具体的Town实例,mock关联方法的返回值:
示例测试代码:
use Mockery; use Illuminate\Database\Eloquent\Relations\HasOne; public function test_town_show_displays_temperature() { $town = Town::factory()->create(); $mockTempView = TemperatureView::make(['current_temp' => 28]); // Mock HasOne关联对象,使其返回预设的视图实例 $relationMock = Mockery::mock(HasOne::class); $relationMock->shouldReceive('first')->andReturn($mockTempView); // 若控制器使用load()方法,需额外mock getResults() $relationMock->shouldReceive('getResults')->andReturn($mockTempView); // 让Town实例的temperatureView方法返回这个mock的关联对象 $town->shouldReceive('temperatureView')->andReturn($relationMock); $response = $this->get(route('town.show', $town)); $response->assertSee('28'); }
注意:必须针对具体的Town实例进行Mock,而非Town类的全局方法——Feature测试中路由模型绑定返回的是数据库中真实创建的实例,类级别的Mock不会作用于该实例。
为什么之前的Mock失败?
你按照官方文档Mock失败,核心原因是Mock了Town类的全局方法或依赖注入的类,但Feature测试中控制器获取的是数据库中真实存在的Town实例,类级别的Mock无法覆盖已实例化对象的方法,必须针对具体实例进行关联设置或Mock。
内容的提问来源于stack exchange,提问作者luca-rigutti
相关产品推荐
相关产品推荐

