I have a command and some methods related to Redis connection are running in it. I want to test some of these methods and for this I want to mock the Redis connection. I approached it like this:
protected function mockRedis(): void
{
$redisConnection = Mockery::mock(Connection::class);
app()->instance(Connection::class, $redisConnection);
Redis::shouldReceive('connection')
->once()
->andReturn($redisConnection);
Redis::connection()
->shouldReceive('client')
->once()
->andReturnSelf();
Redis::connection()
->client()
->shouldReceive('ping')
->once()
->andReturn(true);
Redis::connection()
->client()
->shouldReceive('close')
->once();
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);
});
}
The lines I want to test are as follows:
// some openswoole methods...
// ...
Redis::connection()->client()->ping();
// ...
Redis::connection()->client()->close();
// ...
Redis::subscribe(['socket-data'], function (string $message) {
//...
});
Caught error:
1) Tests\Feature\RedisSubscribeTest::test_redis_subscribe_command
Mockery\Exception\BadMethodCallException: Received Mockery_0_Illuminate_Redis_Connections_Connection::client(), but no expectations were specified
Any idea?
You should set up the expectations for chained calls using andReturnSelf()
and return a new mock for the subsequent chained method.
protected function mockRedis(): void
{
$redisConnection = Mockery::mock(Connection::class);
app()->instance(Connection::class, $redisConnection);
// Set up the initial Redis::connection() expectation.
Redis::shouldReceive('connection')
->once()
->andReturn($redisConnection);
// Set up the chained method calls.
$redisConnection->shouldReceive('client')
->once()
->andReturnSelf();
$clientMock = Mockery::mock(); // Create a mock for the client.
// Expect the ping method on the client mock.
$clientMock->shouldReceive('ping')
->once()
->andReturn(true);
// Expect the close method on the client mock.
$clientMock->shouldReceive('close')
->once();
// Set up the chained method calls.
$redisConnection->shouldReceive('client')
->once()
->andReturn($clientMock);
// Set up the Redis::subscribe expectation.
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);
});
}