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
[code lang="PHP" light="true"] $mock ->expects($this->once()) ->method('myMagicMethod') ->with('123') ->willReturn('myResult'); [/code]
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
[code lang="PHP" light="true"] $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'); [/code]
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 🙂
A bit frustrating ? this was the most frustrating 1h spent in my life 🙂
Thanks for the tip though.
You can also use the setMethods off the mockBuilder to tell phpunit to mock methods that don’t exists in the class.
https://phpunit.de/manual/current/en/test-doubles.html
This, way better way to accomplish it.
+1 for that
Looks more reasonable than mocking __call