Laravel中Mock Repository控制器时all方法调用次数不符的测试问题
问题分析与解决方案
你遇到的InvalidCountException错误,核心原因是测试中Mock的CompanyRepository实例并没有被CompanyController实际使用——控制器依然调用了原始的Repository类,导致mock的all()方法一次都没被触发。
最常见的诱因有两个:一是容器绑定mock的时机太晚,控制器已经提前解析了原始Repository实例;二是类路径拼写错误(你错误信息里的Repostiries明显是Repositories的笔误)。
修正后的测试代码
<?php namespace Test\Unit\Shared\Repositories; use Mockery; use Tests\TestCase; use App\Shared\Repositories\CompanyRepository; use App\Models\Company; class CompanyRepositoryTest extends TestCase { protected $companyRepo; protected function setUp(): void { parent::setUp(); // 提前在setUp中绑定mock,确保控制器解析时优先使用它 $this->companyRepo = Mockery::mock(CompanyRepository::class); $this->app->instance(CompanyRepository::class, $this->companyRepo); } protected function tearDown(): void { Mockery::close(); // 清理mock实例,避免测试污染 parent::tearDown(); } /** * @group mockingrepo3 */ public function test_all() { // 定义mock的预期行为:all方法被调用1次,返回空集合 $this->companyRepo->shouldReceive('all') ->andReturn(collect()) ->once(); // 设置认证用户(确保有权限访问路由) $company = Company::find(3); $this->be($company); // 发起GET请求到目标路由 $response = $this->get(route('app.admin.company.index')); // 额外断言请求成功(避免因权限问题导致控制器方法未执行) $response->assertStatus(200); } }
关键修正说明
- 提前绑定Mock:在
setUp阶段就将mock注入容器,确保控制器在初始化时拿到的是mock实例,而非原始Repository类。 - 使用类常量替代字符串:用
CompanyRepository::class代替硬编码的路径字符串,彻底避免拼写错误(这很可能是你本次问题的直接诱因)。 - 清理Mock实例:在
tearDown中调用Mockery::close(),防止mock实例残留影响后续测试。 - 增加响应断言:通过
assertStatus(200)验证请求未被拦截(比如权限不足导致的重定向),确保控制器方法确实被执行。
额外检查项
- 确认控制器中
CompanyRepository的命名空间正确:// CompanyController顶部必须有正确的use语句 use App\Shared\Repositories\CompanyRepository; - 验证路由
app.admin.company.index确实指向CompanyController@index,没有配置错误。 - 确保
Company::find(3)返回的用户拥有访问该路由的权限,避免请求被重定向到登录页(导致控制器方法未执行)。
内容的提问来源于stack exchange,提问作者mateonunez
相关产品推荐
相关产品推荐

