Search code examples
laravellaravel-5mockingphpunitmockery

stringContains argument matching within Laravel Log facade shouldReceive


I saw in the Laravel docs that it's possible to set a test expectation like this:

Cache::shouldReceive('get')
                ->once()
                ->with('key')
                ->andReturn('value');

Then I saw in the PHPunit docs that flexible argument matching is possible like this: $this->stringContains('Something').

But when I edit my test to have this:

Log::shouldReceive('error')
            ->once();
            ->with($this->stringContains('Contact does not exist'));

...then I get the following error:

Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_1_Illuminate_Log_Writer::error("Contact does not exist blah blah etc"). 
Either the method was unexpected or its arguments matched no expected argument list for this method

How can I accomplish my goal (with flexible argument matching within Log::shouldReceive)?

P.S. I've also tried ->with(\PHPUnit\Framework\Assert::stringContains('Contact does not exist')).


Solution

  • The mocking functionality of facades uses Mockery to generate mock objects. stringContains() is functionality provided by PHPUnit mock objects. These two are not compatible.

    You will need to use argument validation methods provided by Mockery.

    My first attempt would be to use the \Mockery::pattern() matcher which uses regular expressions:

    Log::shouldReceive('error')
        ->once()
        ->with(\Mockery::pattern('/Contact does not exist/'));
    

    Another option would be to use the \Mockery::on() matcher, which allows you to use a Closure to provide complex argument matching logic.

    Log::shouldReceive('error')
        ->once()
        ->with(\Mockery::on(function ($arg) {
            return stripos($arg, 'Contact does not exist') !== false;
        }));