Faster dependency mocking 03

I’m trying to approach the problem of dependency mocking from another side and come up with a lateral solution to the problem based on ad-hoc adapters.

The problem

While developing for WordPress I’ve been using adapter class to abstract my objects for globally defined functions and methods, see tad_FunctionsAdapter and tad_GlobalsAdapter classes in the tdd-helpers package, and those will rely almost exclusively on the explicit implementation of the magic __call method adapter objects will offer.
The __call method defined in the tad_FunctionsAdapter class is nothing more complicated then

public function __call($function, $arguments)
{
    return call_user_func_array($function, $arguments);
}

and it’s the only method the class will define.
The interface the class implements is not any richer

interface tad_FunctionsAdapterInterface
{
    public function __call($function, $arguments);
}

Given a class and its test case like this:

// file AdapterDependingObject.php

class AdapterDependingObject {
    protected $functionsAdapter;

    public function __construct(tad_FunctionsAdapterInterface $functionsAdapter $f = null){
        $this->functionsAdapter = $f ? $f : new tad_FunctionsAdapter();
    }

    public function someMethod(){
        if($this->functionsAdapter->one(1)){
            $this->functionsAdapter->two(2);
        }
        $this->functionsAdapter->three(3);
        $this->functionsAdapter->four(4);
    }
}

// AdapterDependingObjectTest.php

class AdapterDependingObjectTest extends PHPUnit_Framework_TestCase{

    public function testSomeMethod(){
        // explicit stubbing
        $mockFunctionsAdapter = $this->getMockBuilder('tad_FunctionsAdapterInterface')
            ->setMethods(array('__call', 'one', 'two', 'three', 'four'))
            ->getMock();

        // stubbin return values
        $mockFunctionsAdapter->method('one')
            ->willReturn(false);
        $mockFunctionsAdapter->expects($this->never())
            ->method('two');

        // these I stub to make it work, not for test sake
        $mockFunctionsAdapter->method('three');
            ->willReturn(9);
        $mockFunctionsAdapter->method('four');
            ->willReturn(16);

        $sut = new AdapterDependingObject($mockFunctionsAdapter);

        $sut->someMethod();
    }
}

explicit stubbing of the methods is required or those would not be defined at all on the adapter and their invocation would throw an exception. Explicit method mocking should instead be used to set expectations and return values on some methods while leaving the other methods intact and normal functioning and that’s not the case here.

Ad-hoc adapters

Writing new adapters like the one below would make my testing life easier and would make future code maintenance and modification possible on a per-object basis.

// file Adapter.php

interface Adapter {
    // no methods
}

// file AdHocAdapter.php

class AdHocAdapter implements Adapter {

    public function one($arg){
        return one($arg);
    }

    public function two($arg){
        return two($arg);
    }

    public function three($arg){
        return three($arg);
    }

    public function four($arg){
        return four($arg);
    }

}

// file AdapterDependingObject.php

class AdapterDependingObject {
    protected $functionsAdapter;

    public function __construct(Adapter $functionsAdapter $f = null){
        $this->functionsAdapter = $f ? $f : new AdHocAdapter();
    }

    public function someMethod(){
        if($this->functionsAdapter->one(1)){
            $this->functionsAdapter->two(2);
        }
        $this->functionsAdapter->three(3);
        $this->functionsAdapter->four(4);
    }
}

// AdapterDependingObjectTest.php

class AdapterDependingObjectTest extends PHPUnit_Framework_TestCase{

    public function testSomeMethod(){
        // explicit stubbing
        $mockFunctionsAdapter = $this->getMock('AdHocAdapter');

        // stubbing return values
        $mockFunctionsAdapter->method('one')
            ->willReturn(false);
        $mockFunctionsAdapter->expects($this->never())
            ->method('two');

        // no stubbing of three and four, will act normally

        $sut = new AdapterDependingObject($mockFunctionsAdapter);

        $sut->someMethod();
    }
}

I will be able to stub or mock methods as before but will also be able to use a test suite like phpspec to write my tests: I had experimented with it and left it behind when I found out that it would only mock explicitly defined public objects methods, my adapters were out of the game.

Next: I do not want to write lengthy adapters

Magic method based adapters were born out of the frustration of having to write the same code over and over to do the same thing. I’d like to be able to automate that process and have a reliable way to write ad hoc adapters on a per-project or per-class basis.