Mocking magic methods with PHPUnit

Reading Time: < 1 minute

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
    -&gt;expects($this-&amp;amp;gt;once())
    -&gt;method('myMagicMethod')
    -&gt;with('123')
    -&gt;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
    -&gt;expects($this-&amp;amp;gt;once())
    -&gt;method('__call')
    // Be sure to pass the method argument(s)
    // as array, even if you only have one
    // argument!
    -&gt;with(
        $this-&gt;equalTo('myMagicFunction'),
        $this-&gt;equalTo(['123'])
    )
    -&gt;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 🙂

4 thoughts on “Mocking magic methods with PHPUnit”

Leave a Reply

Your email address will not be published. Required fields are marked *

I accept the Privacy Policy

This site uses Akismet to reduce spam. Learn how your comment data is processed.