Logan Bailey

Adventures In Web Development

Blog, About, GitHub, and LinkedIn

Whenever I create a new test, I tend to follow the same format. Create a setUp method, declare all my mocks. Then inject the mocks into the unit of code I'm testing. My IDE's static code analyzer would always complain about parameter type mismatches. Mainly, that I was supplying instances of MockObject rather than *Interface. Fortunately, I came across a nice solution that fixed the analyzer warnings as well as preserved my IDE auto completion.

<?php

namespace Acme\Project;

use GuzzleHttp\Client;
use PHPUnit_Framework_TestCase;
use PHPUnit_Framework_MockObject_MockObject as MockObject;

class ApiWrapperTest extends PHPUnit_Framework_TestCase
{
    /** @var Client|MockObject */
    protected $http;
    
    /** @var ApiWrapper */
    protected $client;

    public function setUp()
    {
        $this->http = $this->createMock(Client::class);
        $this->wrapper = new ApiWrapper($this->http);
    }
}

There are two important changes here. I've included the aliased namespace, PHPUnit_Framework_MockObject_MockObject as MockObject. This makes my docblock type hints easier to read. Next, I've specified that my mock objects are not only instances of MockObject but also of their mocked class, Client|MockObject. This means the property can either be an instance of Client or MockObject. My IDE's static code analyzer no longer complains about parameter type mismatches and I still have code completion for my mock.

I haven't memorized the MockObject namespace for PHPUnit, instead I've created a PHPStorm Live Template, basically a macro. Anytime I type um↹, my IDE will print use PHPUnit_Framework_MockObject_MockObject as MockObject to the screen. This was enough to do and the steps taken can be seen in the image below: