Mocking magic methods with PHPUnit
Updated: as pointed out in the comments below, using setMethods() or, since this function is deprecated lately, addMethods(), is the much better way for the mocking of magic methods with PHPUnit!
$mock = $this
->getMockBuilder(MyClass::class)
->addMethods(['myMagicMethod'])
->getMock();
$mock
->expects($this->once())
->method('myMagicMethod')
->willReturn('myResult');
$this->assertEquals('myResult', $mock->myMagicMethod());
Original post: If you want to test a method of an object which is supplied using the magic method __call(), you can’t simply mock the desired method. You have to go the longer way via __call(). So e.g. if your magic method you want to mock is called “myMagicFunction”, you could be tempted to write
$mock
->expects($this->once())
->method('myMagicMethod')
->with('123')
->willReturn('myResult');
since, after all, it is a mock, right? So why wasting time? Obviously PHPUnit (Version 4.5.0 at the time of writing) is doing some sort of internal checks, preventing our laziness and forcing us to mock the __call() method instead. I can only guess the reason here, any comments with more insight on this topic are highly appreciated!
Of course, mocking the __call() method instead is not much more work
$mock
->expects($this->once())
->method('__call')
// Be sure to pass the method argument(s)
// as array, even if you only have one
// argument!
->with(
$this->equalTo('myMagicFunction'),
$this->equalTo(['123'])
)
->willReturn('myResult');
However PHPUnit will not throw any Exceptions if you use the first approach, instead it will only return NULL instead the expected ‘myResult’. This can be a bit frustrating :-)