Mockery模拟Redis连接时抛出BadMethodCallException错误排查
解决Mockery中Redis Connection的
client()方法未设置期望的错误 问题原因
你在设置client()、ping()、close()这些方法的期望时,使用了Redis::connection()->shouldReceive(...)的链式写法,这种方式会导致期望没有正确绑定到你预先创建的$redisConnection mock实例上。当实际代码调用Redis::connection()->client()时,mock找不到对应的期望定义,就抛出了BadMethodCallException。
修复后的代码
修改mockRedis()方法,直接用一开始创建的$redisConnection变量来设置所有Connection实例的方法期望:
protected function mockRedis(): void { $redisConnection = Mockery::mock(Connection::class); app()->instance(Connection::class, $redisConnection); // 设置Redis facade的connection方法返回我们的mock实例 Redis::shouldReceive('connection') ->once() ->andReturn($redisConnection); // 直接用$redisConnection设置client()方法的期望 $redisConnection->shouldReceive('client') ->twice() // 实际代码调用了两次client():一次ping,一次close ->andReturnSelf(); // 基于$redisConnection的client返回值设置ping期望 $redisConnection->client()->shouldReceive('ping') ->once() ->andReturn(true); // 设置close期望 $redisConnection->client()->shouldReceive('close') ->once(); // 设置subscribe的期望 Redis::shouldReceive('subscribe') ->once() ->with(['socket-data'], Mockery::type('callable')) ->andReturnUsing(function ($channels, $callback) { $message1 = json_encode([ 'type' => 'alive', 'interval' => 10, 'time' => '2023-10-04T10:00:00+00:00', ]); $message2 = json_encode([ 'type' => 'some_type', 'data' => 'some_data', ]); $callback($message1); $callback($message2); }); }
关键修改点
- 将
Redis::connection()->shouldReceive('client')改为$redisConnection->shouldReceive('client'),确保期望绑定到正确的mock实例 - 调整
client()方法的调用次数:实际代码中调用了两次(一次用于ping(),一次用于close()),所以把原有的once()改为twice(),避免后续出现“方法调用次数不匹配”的错误
内容的提问来源于stack exchange,提问作者tyki
相关产品推荐
相关产品推荐

