You are currently browsing the Test Me posts tagged: Mock Objects


Mockery Test Case for PHPUnit

Mockery is a wonderful PHP mock object framework. It reminds me of Mockito for Java.

Mockery is far more fluent than MockObjects, the mock object framework packaged with PHPUnit. Mockery and MockObjects can work in the same environment, independent of one another.

Since Mockery is a free standing library, it can be used in PHPUnit, but you need to make sure you either have a loader that supports Mockery or use a bootstrap.php to use the loader packaged with Mockery. You will also need to consider using the TestListener packaged with Mockery to avoid having to remember to call Mockery::close() in tearDown for each TestCase, and a TestListener requires a PHPUnit XML configuration file.

All of this is do-able, but just not fun.

Now there is another alternative:

PHPUnit_Extensions_Mockery_TestCase

Using this new test case eliminates the bootstrap.php, TestListener with XML configuration, and explicit static calls to Mockery if you use Hamcrest matchers instead of Mockery matchers.

There is even a short hand for initializing mockery mocks, and support for counting Mockery expectations as assertions for better --strict mode support.

Check it out in the latest release of Etsy PHPUnit Extensions.

Testing Your Mocks

Very few times, is it OK to write your own mock class, by hand, for an existing class.  We’ll save the nitty gritty of that statement for a later rant.  

If you happen across the very rare instance that you need a hand-written mock, then you will definitely want to write a unit test for your mock.  Otherwise, in a unit test, you should never test a mock.

Many times I have seen this awful pattern.  

There is a class like so

<?php

class MyClass {

     public function doAwesome() {

         $param1 = ... // compute this
         $param2 = ... // compute this

         $silly_bar = $this->doSomethingIDontWantToDoWhenITest($param1, $param2);

          return $silly_bar;
    }

    protected function doSomethingIDontWantToDoWhenITest($param1, $param2) {

        // Literally -- Do something that I don't want to do when I test doAwesome

    }
}
?>

with a test like so

<?php

require_once 'AutoLoader.php';

class MyClassTest extends PHPUnit_TestCase_Framework {

    function testDoAweome() {
        $my_obj = new MyClassMock();
        $this->assertEquals("I'm awesome", $my_obj->doAwesome());
    }

}

class MyClassMock extends MyClass {

    /**
      * We'll just return some string to make sure this gets called.
      */
    protected function doSomethingIDontWantToDoWhenITest($param1, $param2) {
          return "I'm awesome";
    }
}
?>

First, if I look at the test, it looks like I am testing a MyClassMock, and not MyClass.

Maybe I should rename this test to MyClassMockTest. WRONG

Why are you testing the mock?
The mock isn’t going to be used anywhere!

Why did the person even write this mock in the first place?
MyClass calls doSomethingIDontWantToDoWhenITest in the doAwesome method that I actually want to test, so if we make the doSomethingIDontWantToDoWhenITest method protected, then I can extend MyClass and override doSomethingIDontWantToDoWhenITest to return something simple without doing any work.

So clever, but SO WRONG!
This is wrong, and this example has put us in an awful trap.
The method doAwesome computes $param1 and $param2 before passing them to doSomethingIDontWantToDoWhenITest and returns the result of that call. Our MyClassMock does not take into account what got computed for $param1 and $param2. Sure, we executed the code to compute $param1 and $param2, but we only verified the results of the mock implementation of doSomethingIDontWantToDoWhenITest. * Slaps Forehead *

How do we fix this?
We have uncovered that doSomethingIDontWantToDoWhenITest is essentially begging for the Strategy Pattern.

Essentially, we need to extract method into a new object, like so

<?php

class MyStrategy {

    public function doSomethingIDontWantToDoWhenITest($param1, $param2) {

        // Literally -- Do something that I don't want to do when I test doAwesome

    }
}
?>

and modify MyClass like so

<?php

class MyClass {

    private $strategy;

    public MyClass($strategy) {
        $this->strategy = $strategy;
    }

    public function doAwesome() {

        $param1 = ... // compute this
        $param2 = ... // compute this

        $silly_bar = $this->strategy->doSomethingIDontWantToDoWhenITest($param1, $param2);

         return $silly_bar;
    }
}
?>

and modify the test, like this

<?php

class MyClassTest extends PHPUnit_Framework_TestCase {

    function testDoAwesome() {
        $param1 = ... // what the value of this should be computed by doAwesome to be
        $param2 = ... // what the value of this should be computed by doAwesome to be
        $strategy = $this->getMock('MyStrategy');
        $strategy
            ->expects($this->once())
            ->method('doSomethingIDontWantToDoWhenITest')
            ->with($param1, $param2)
            ->will($this->returnValue("I'm truly awesome"));

        $my_object = new MyClass($strategy);
        $this->assertEquals("I'm truly awesome", $my_object->doAwesome());
}
?>

The PHPUnit mock object library in this case will verify that the method doSomethingIDontWantToDoWhenITest is called once, with what we expect doAwesome will compute $param1 and $param2 to be, and will then return a value that we can verify gets returned un-altered.

EXTRA BONUS !!!
Besides no longer be confused about what is actually being tested. I improved the re-usability of MyClass. Anyone can now make several MyClass objects that handle $param1 and $param2 differently because anyone can implement whatever strategy he wants by simply composing a new MyClass at construction time with a different strategy.

If you find yourself writing a mock, stop and think. You almost always can re-work your code into something that is more extensible and re-usable with a side benefit of better testability.


Tags