#native_company# #native_desc#
#native_cta#

Working with PHPUnit Test Helpers

By John Barlow
on January 30, 2015

In the first two articles (Test Driven Development with PHPUnit and Advanced Mocking with PHPUnit) I gave an introduction to PHPUnit and how to do object mocking. While necessary, sometimes all of the setup work can become tedious for large projects. In this article, I hope to show how some helper methods can make test writing much easier and faster.

Test Setup — An Easier Way

In our previous examples, I outlined how to set up a basic unit test, and how you can do mocking inside of that test to isolate functionality. For small classes this is fine, but for more complicated code there could be a lot of setup involved in each test.

For example, if you wanted to test class A, which happened to have as members classes B, C, and D, each test would have to set up mock objects of B, C, and D before A could be tested (assuming every function in A called one of these classes). With that in mind, there would be a lot of repeated code in each test just for the sake of setting up the test. As the rule goes, if you are copying and pasting, you’re doing something wrong.

Thankfully, PHPUnit has a helper method that takes care of this for us: the setup() method. This method is called before every test, so it can be used for things such as constructing all of the supporting mock objects needed. Assuming that class A contains the other classes as public members, we can do this:

<?php
class myTest extends PHPUnit_Framework_TestCase
{
    protected B;
    protected C;
    protected D;

    protected function setUp()
    {
        $this->B = $this->getMockBuilder('B');
        $this->C = $this->getMockBuilder('C');
        $this->D = $this->getMockBuilder('D');
    }

    public function testA()
    {
        $A = $this->getMockBuilder('A');
        $A->B = $this->B;
        $A->C = $this->C;
        $A->D = $this->D;

        //Do test stuff here
    }
 }
 ?> 

In the example above, the setup function (which is called before every test), objects B, C, and D are created as mocks and assigned to the current running test object as class variables. From there, when the test actually runs, we can create a mock of the class we want to test that uses them and assign them accordingly to the new mock object.

Since most everything is done by reference in PHP, if you need to add additional functionality to the mocks, you can easily do that through the class variables and the mock object A will reflect those changes. For example, if there was a foo function in object B that we wanted to return a specific value for a test:

$this->B->expects($this->any())
            ->method('foo')
            ->will($this->returnValue('bar')); 

After that line, our test that invokes B->foo() will have the value ‘bar’ returned. If this is a desired behavior across all tests, that can be moved to our setup() function and every test will have this override available to it.

What About Protected or Private Members?

I had mentioned in the example above that if the members were public, we could just assign them to the mock and use them. However, in the real world, B, C, and D would most likely be private or protected members of the class, so we couldn’t just assign them from the outside. If A implemented getters and setters, we could easily just use those for the assignment. However, if the classes are more internal to A (or set dynamically) we have to employ some other methods to set them — reflection.

To use reflection, there is a little setup involved, but the general idea is this: we need to tell PHP that we are looking into the class, and for it to expose a protected member for use to act upon. This could be accessing class members, or functions.

Using reflection starts by creating a ReflectionClass objet based on the object in which you wish to reflect. In our case, we will use the mock stored in the $A variable.

$reflection = new ReflectionClass($A); 

After we have the object, we need to get a handle to the members we want to act upon.

$reflectedB = $reflection->getProperty('B'); 

Now that we have a handle, we can set it to accessible and change the value.

$reflectedB->setAccessible(true);
$reflectedB->setValue($this->B); 

Using those four lines, you can access a protected or private member of a class and change its value.

One Final Thought — Teardown

I would be remiss if I didn’t mention the tearDown() function after talking up setUp(). Teardown is the counterpart to setup as it is ran AFTER every test. This is useful for undoing any changes your tests may do to an app. One very obvious test case involves a data layer. If you are writing tests for a data layer, then you are most likely writing data to the database (as you would have to for a complete test). If you keep track of the rows written, you could easily use tearDown() to remove those after the test completes. Another use case is to de-allocate any variables used in prior tests so the garbage collector can clean things up a bit.

I make very liberal use of setup in my unit tests. It makes testing complicated objects tolerable to say the least. In some cases it could make things more complicated, but I still have a few tricks up my sleeve to share to handle these edge cases. Until next time.