Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit test function with value passed by reference and a returned value

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

like image 835
Alessandro Minoccheri Avatar asked Sep 01 '26 13:09

Alessandro Minoccheri


1 Answers

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.

like image 58
Schleis Avatar answered Sep 03 '26 05:09

Schleis



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!