Testing all those super constructors WordPress loves

In WordPress object-oriented development the following sight is not uncommon

class SomeClass
{
    public function __construct()
    {
        add_action('someAction', array($this, 'someMethod'));
    }
}

and, in a quick glance I see test-ability drop to the ground. But there’s hope.

Adapter classes

Adapter classes are nothing new and I’ve implemented one for globally defined functions in my libraries.
Such classes will essentially wrap and call a globally defined function via a pretty simple __call magic method

<?php
namespace tad\adapters;

class Functions implements \tad\interfaces\FunctionsAdapter
{
    public function __call($function, $arguments)
    {
        if (!is_string($function) or !function_exists($function)) {
            return;
        }
        return call_user_func_array($function, $arguments);
    }
}

Testable constructors

To make that code testable, easily and in isolation, SomeClass needs to be changed into

<?php
class SomeClass
{
    protected $functions;

    public function __construct(\tad\interfaces\FunctionsAdapter $functions = null)
    {
        if(is_null($functions)) {
            $functions = new \tad\adapters\Functions();
        }
        $this->functions = $functions;

        // now add the actions via the adapter
        $this->functions->add_action('someAction', array($this, 'someMethod'));
    }
}

The null default argument will allow the class to be constructed in production code with no arguments and will leave the possibility to inject a dependency in it at development and testing time like

<?php
class SomeTest extends \PHPUnit_Framework_TestCase
{
    public function testWillCallAddActionAtConstructTime()
    {
        // stub the object to test to control when and where the __construct method will be called
        // 'sut' stands for 'subject under test' or 'system...'
        $sutStub = $this->getMockBuilder('SomeClass')->disableOriginalConstructor()->getMock();

        // get a mock of the functions interface
        // mock the __call method to avoid having it fire first
        // mock the method(s) the sut will/should call
        $mockFunctions = $this->getMock('\tad\interfaces\FunctionsAdapter', array('__call', 'add_action')); 

        // set an expectation on the functions mock
        $mockFunctions->expects($this->once())->method('add_action')->with('someAction', array($sutStub, 'someMethod'));

        // finally call the __construct method and verify that expectation
        $sutStub->__construct($mockFunctions);
    }
}

That’s really it to make all those __construct-time, sometimes unavoidable, calls testable.