Mocking the response only for a certain parameter

3.6k views Asked by At

I have a class where I am mocking the get method when called with test1 to return 123. This works fine.

However, I want to have all other calls to the get method return what would normally be returned - i.e. only a call with a specific parameter returns a mock response.

$configMock = m::mock(Config::class);

$configMock->shouldReceive('get')
        ->with('test1')
        ->andReturn(123);

So if I call get with a different parameter in the code i.e. $config->get('test2') I get the error

Mockery\Exception\NoMatchingExpectationException: No matching handler found for Mockery_1_Illuminate_Contracts_Config_Repository::get("test2"). Either the method was unexpected or its arguments matched no expected argument list for this method

However when I use ->makePartial() on the first line, at the line $config->get('test2') I get the error

BadMethodCallException: Method Mockery_1_Illuminate_Contracts_Config_Repository::get() does not exist on this mock object

How can I mock a method response for only a certain parameter being passed whilst letting that method return normal responses for all other calls to that method?

3

There are 3 answers

0
myol On BEST ANSWER

I ended up taking @Loeks advice. There might be a cleaner way to do this but this is working for me.

    $config = new Config;

    $closure = function ($arg) use ($config) {
        switch ($arg) {
            case 'test1':

                return 123;
            default:
                // Return default values

                return $config->get($arg);
        }
    };

    $configMock = m::mock(Config::class)
        ->makePartial();

    $configMock->shouldReceive('get')
        ->andReturnUsing($closure);
5
Loek On

I personally think that one should exactly specify what you want to happen in every test function. So basically that is:

$configMock->shouldReceive('get')
           ->with('test2')
           ->andReturn(INSERT_CORRECT_RESPONSE);

Note that this leads to quite some code duplication if you have a lot of test functions doing this, so you might want to extract it to another method:

private function testCorrectResult($parameter)
{
    $configMock = m::mock(Config::class);

    if ($parameter === 'test1') {
        $configMock->shouldReceive('get')
                   ->with('test1')
                   ->andReturn(123);
    } else {
        $configMock->shouldReceive('get')
                   ->with('test2')
                   ->andReturn(INSERT_CORRECT_RESPONSE);
    }
}

This is what I believe your question was about, let me know if I got it wrong!

0
Yevgeniy Afanasyev On

You can chain '->shouldReceive('get')' multiple times and feed >andReturn( with what you really need this time.

You should avoid putting any logic to unit test using the order of the called function instead.