Symfony单元测试报错:方法期望调用1次实际调用0次排查
问题原因
测试不通过是两个逻辑错误导致Mock完全没生效:
- 执行顺序反了:你先调用
$this->client->request()发起了接口请求,整个控制器逻辑都跑完了才创建Mock对象,此时真实仓储的删除方法早就执行完了,Mock根本碰不到调用逻辑。 - 没有把Mock注入容器:你创建的Mock只是测试方法里的局部变量,从来没有替换掉框架服务容器里的真实仓储实例,控制器里调用
$this->postRepository()拿到的还是原来的真实对象,和你创建的Mock没有任何关联,自然统计不到调用次数。
修复后的测试代码
把Mock创建、容器替换的步骤移到发起请求之前,确保请求进来时控制器拿到的就是你配置了期望的Mock对象:
public function testDelete() { $postId = PostDataSeeder::POST_ID; // 先创建Mock、配置调用期望,必须在发请求前完成 $postRepositoryMock = $this->createMock(PostRepository::class); $postRepositoryMock ->expects($this->once()) ->method('deletePost') ->with($postId); $commentsRepositoryMock = $this->createMock(CommentsRepository::class); $commentsRepositoryMock ->expects($this->once()) ->method('deleteComments') ->with($postId); // 将Mock替换到服务容器,覆盖原来的真实实例 // 以下是Symfony框架的容器替换写法,如果你用其他框架,替换对应容器内的服务即可 $this->client->getContainer()->set(PostRepository::class, $postRepositoryMock); $this->client->getContainer()->set(CommentsRepository::class, $commentsRepositoryMock); // 构造路由发起请求 $route = $this->getUrl('api_delete_post', [ '_format' => 'json', 'postId' => $postId ]); $this->client->request('DELETE', $route, [], [], [ 'CONTENT_TYPE' => 'application/json', ]); // 可选:补充断言响应状态码符合预期 $this->assertResponseStatusCodeSame(204); }
额外说明
- 如果你的
postRepository()、commentsRepository()方法是直接new实例而不是从容器取,需要先调整控制器的获取逻辑,统一从服务容器拉取依赖,否则Mock永远无法接管真实调用。 - 不需要在测试里提前调用
findOne查真实文章实体,你要验证的只是删除方法被正确ID调用,直接用种子里定义的常量ID即可,多余的数据库查询会拖慢单元测试速度,还可能引入数据依赖导致的偶发报错。
内容的提问来源于stack exchange,提问作者Zak
相关产品推荐
相关产品推荐

