Laravel控制器测试:如何Mock内部调用的服务方法
Laravel控制器测试中Mock服务层方法的实现指导
场景说明
你在Laravel项目中测试PageController的renderAboutUsPage方法时,需要MockPageService的getActivePageBySlug方法,避免触发真实的数据库查询,同时你已经单独完成了服务层方法的测试。
具体实现步骤
要Mock服务层方法,我们可以借助Laravel内置的Mockery工具,通过容器绑定替换真实的服务实例,具体操作如下:
1. 构建模拟的Page模型实例
首先创建一个模拟的Page模型对象,作为Mock服务方法的返回值:
$mockPage = Mockery::mock(Page::class);
2. Mock PageService的目标方法
创建PageService的模拟实例,指定getActivePageBySlug方法的调用规则:
$pageServiceMock = Mockery::mock(PageService::class); $pageServiceMock->shouldReceive('getActivePageBySlug') ->once() // 验证方法被调用一次 ->with('about-us') // 验证传入的slug参数正确 ->andReturn($mockPage); // 指定方法返回模拟的Page实例
3. 将Mock实例绑定到Laravel容器
通过容器绑定,让控制器构造函数注入的是Mock服务而非真实实例:
$this->app->instance(PageService::class, $pageServiceMock);
4. 调整测试断言
由于Mock了服务层方法,服务层内部的日志(Getting page by active status and provided slug.)不会执行,需要删除对应的日志断言,否则测试会失败。
修改后的完整测试用例
/** * @test * @testdox 关于我们页面是否成功响应、渲染正确视图、包含view对象{data}并记录正确日志 * @group website * @group static-pages */ public function test_whether_about_us_page_renders_successfully() { // 创建模拟的Page模型实例 $mockPage = Mockery::mock(Page::class); // Mock PageService并指定方法行为 $pageServiceMock = Mockery::mock(PageService::class); $pageServiceMock->shouldReceive('getActivePageBySlug') ->once() ->with('about-us') ->andReturn($mockPage); // 绑定Mock实例到容器 $this->app->instance(PageService::class, $pageServiceMock); // 断言控制器中的日志记录 Log::shouldReceive('info')->once()->with("Rendering about-us static page."); // 发起请求 $response = $this->get('about-us'); // 响应与视图断言 $response->assertStatus(200); $response->assertViewIs('pages.static-page'); $response->assertViewHas('data', $mockPage); // 验证视图数据为模拟实例 }
扩展:异常场景测试
如果需要测试服务层抛出异常的情况(比如页面不存在),可以用andThrow()指定抛出的异常:
$pageServiceMock->shouldReceive('getActivePageBySlug') ->once() ->with('about-us') ->andThrow(new NotFoundHttpException()); // 断言响应状态为404 $response->assertStatus(404);
内容的提问来源于stack exchange,提问作者Nishant
相关产品推荐
相关产品推荐

