6

Hi all I need to test a piece of code that call a function of another class that I can't edit now.

I need only to test It but the problem is that this function has a values passed by reference and a value returned, so I don't know how to mock It.

This is the function of column class:

    public function functionWithValuePassedByReference(&$matches = null)
    {
        $regex = 'my regex';

        return ($matches === null) ? preg_match($regex, $this->field) : preg_match($regex, $this->field, $matches);
    }

This is the point where is called and where I need to mock:

    $matches = [];
    if ($column->functionWithValuePassedByReference($matches)) {
        if (strtolower($matches['parameters']) == 'distinct') {
            //my code
        }
    }

So I have tried

   $this->columnMock = $this->createMock(Column::class);
   $this->columnMock
        ->method('functionWithValuePassedByReference')
        ->willReturn(true);

If I do this return me error that index parameters doesn't exist obviously so I have tried this:

   $this->columnMock = $this->createMock(Column::class);
   $this->columnMock
        ->method('functionWithValuePassedByReference')
        ->with([])
        ->willReturn(true);

But same error, how can I mock that function?

Thanks

1 Answer 1

14

You can use ->willReturnCallback() to modify the argument and also return a value. So your mock would become like this:

$this->columnMock
        ->method('functionWithValuePassedByReference')
        ->with([])
        ->willReturnCallback(function(&$matches) {
           $matches = 'foo';
           return True;
         });

In order for this to work, you will need to turn off cloning the mock's arguments when you build the mock. So your mock object would be built like so

$this->columnMock = $this->getMockBuilder('Column')
      ->setMethods(['functionWithValuePassedByReference'])
      ->disableArgumentCloning()
      ->getMock();

This really is code smell, btw. I realize that you stated that you can't change the code that you are mocking. But for other people looking at this question, doing this is causing side effects in your code and can be a source of very frustrating to fix bugs.

Sign up to request clarification or add additional context in comments.

1 Comment

Thank you for this answer - even 5+ years later, it helps. While i agree about code smell and likely hidden side effects, it frustrates me to see language features called out as bad. OP acknowledged it's not ideal, most developers who care about UT know it's not, but it's in the language and has legit uses. Sometimes going the long way around a solution to avoid a smell is itself a smell: over-engineering. Not barking at you, just venting a little. Thanks again!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.