I am writing a test for a console command. In the command we make 2 separate api calls to external services which I can mock fine. But both of those external calls are wrapped in Cache::remember
. I want to able to mock both of those Caches in my test, but can't seem to figure it out. I can only seem to mock the first one. They have different keys.
So for example, my console command has something like this (which I have simplified for the this)
Cache::remember("key-1", (60 * 60) * 24, function () use ($variable) {
return $this->externalApiAdapter->makeApiCall($variable);
});
Cache::remember("key-2", (60 * 60) * 24, function () {
return $this->secondExternalApiAdapter->makeAnotherApiCall();
});
In my test, I want one of the Caches to return null
, and the other to return a mocked object.
Here is the first one.
Cache::shouldReceive('remember')
->with('key-1', (60 * 60) * 24, \Closure::class)
->andReturn(null);
If I out put the second one in
$mockedObject = json_encode([
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
]);
Cache::shouldReceive('remember')
->with('key-2', (60 * 60) * 24, \Closure::class)
->andReturn((object)json_decode($mockedObject));
it sill returns null.
How can I mock the second Cache please.
You can use ->once()
for such purposes.
// This will be returned the first time Cache::remember is called
Cache::shouldReceive('remember')
->once()
->with('key-1', (60 * 60) * 24, \Closure::class)
->andReturn(null);
$mockedObject = json_encode([
'key1' => 'value1',
'key2' => 'value2',
'key3' => 'value3'
]);
// This will be returned the second time Cache::remember is called
Cache::shouldReceive('remember')
->once()
->with('key-2', (60 * 60) * 24, \Closure::class)
->andReturn((object)json_decode($mockedObject));
OK, this was me being a bit silly but after a few hours staring at the code and the docs I figured this out.
In my example I don't need to mock the Caches, since the methods inside the Caches are already mocked. Plus I wasn't returning any value from the Cache methods.
In my command, the Cache::remember
blocks are in there own method, but I wasnt returning anything.
So this
public function methodOne ()
{
Cache::remember("key-1", (60 * 60) * 24, function () use ($variable) {
return $this->externalApiAdapter->makeApiCall($variable);
});
}
public function methodTwo ()
{
Cache::remember("key-2", (60 * 60) * 24, function () {
return $this->secondExternalApiAdapter->makeAnotherApiCall();
});
}
got updated to this
public function methodOne ()
{
return Cache::remember("key-1", (60 * 60) * 24, function () use ($variable) {
return $this->externalApiAdapter->makeApiCall($variable);
});
}
public function methodTwo ()
{
return Cache::remember("key-2", (60 * 60) * 24, function () {
return $this->secondExternalApiAdapter->makeAnotherApiCall();
});
}
In my test I just Cache::flush();
and continue with the mocked classes I already had in place.