Reputation: 35973
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
Upvotes: 6
Views: 3082
Reputation: 43700
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.
Upvotes: 14