1

I'm trying to mock the Cache::put() facade. But it gives me an error. I have tried different ways but couldn't figure it out.

public function testGetAllFromDatabase()
{
    $industry = new Industry();

    Cache::shouldReceive('has')
        ->once()
        ->with('industries.all')
        ->andReturn(false);

    Cache::shouldReceive('put')
        ->with('industries.all', '', 0)
        ->andReturn(true);

    $this->industryMock
        ->shouldReceive('all')
        ->once()
        ->andReturn(array_reverse($this->industries));

    $this->app->instance(Industry::class, $this->industryMock);

    $industryRepository = new IndustryRepository();
    $all = $industryRepository->all();
    dd($all);
    $this->assertContains( $this->industries[2], $all);
}

But when I execute it the following error is occurring.

$ vendor/bin/phpunit
PHPUnit 7.2.7 by Sebastian Bergmann and contributors.

...E                                                                4 / 4 (100%)

Time: 3.76 seconds, Memory: 12.00MB

There was 1 error:

1) Tests\Unit\RepositoriesTests\IndustryRepositoryTest::testGetAllFromDatabase
Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_1_Illuminate_Cache_CacheManager::put('industries.all', object(Illuminate\Database\Eloquent\Collection), '1440'). Either the method was unexpected or its arguments matched no expected argument list for this method

Objects: ( array (
  'Illuminate\\Database\\Eloquent\\Collection' =>
  array (
    'class' => 'Illuminate\\Database\\Eloquent\\Collection',
    'properties' =>
    array (
    ),
  ),
))

F:\development\consulting.local\src\vendor\mockery\mockery\library\Mockery\ExpectationDirector.php:92
F:\development\consulting.local\src\vendor\laravel\framework\src\Illuminate\Support\Facades\Facade.php:223
F:\development\consulting.local\src\app\Repositories\IndustryRepository.php:30
F:\development\consulting.local\src\tests\Unit\RepositoriesTests\IndustryRepositoryTest.php:81

I have tried many ways but couldn't get it to fix. Thank you.

Achintha Samindika
  • 1,944
  • 1
  • 20
  • 31
  • `put` was called with `industries.all` but also a collection and 1440 as parameters 2 and 3 so didn't match `'', 0` that you specified. If you don't care about the parameters 2 and 3 use `$this->anything()` for them – apokryfos Aug 04 '18 at 06:46
  • @apokryfos: DId you mean Cache::shouldReceive('put') ->with('industries.all', $this->anything(), $this->anything()) ->andReturn(true); – Achintha Samindika Aug 04 '18 at 06:53
  • yes, though that works for [PHPUnit's test doubles](https://phpunit.de/manual/6.5/en/test-doubles.html). With [Mockery](http://docs.mockery.io/en/latest/index.html) you may need to use `\Mockery::any()` instead – apokryfos Aug 04 '18 at 06:54
  • Thanks, it worked. – Achintha Samindika Aug 04 '18 at 07:10

2 Answers2

4

Since it may help others, Laravel's facade includes helper functions that allow swapping then with a Mockery test double

This means that when you use a shouldReceive you can chain it with any Mockery expectation for example in this case if you don't care about some parameters you can use:

Cache::shouldReceive('put')
    ->with('industries.all', \Mockery::any(), \Mockery::any())
    ->andReturn(true);
apokryfos
  • 38,771
  • 9
  • 70
  • 114
0

In case it helps others, it's good to point out that you may not want to mock Cache, but instead actually use the real Cache.

That's because it's a Cache for testing only:

When running tests via vendor/bin/phpunit, Laravel [....] automatically configures the session and cache to the array driver while testing, meaning no session or cache data will be persisted while testing.
https://laravel.com/docs/8.x/testing#environment


Note that unlike the OP's test, you may need to follow Laravel's guidance about your test class extending their TestCase to get the behavior, e.g.

use PHPUnit\Framework\TestCase;

class ExampleTest extends TestCase
Daryn
  • 4,791
  • 4
  • 39
  • 52