PHP Unit Tests with FireTest and FireDI

As we talked about before, at UA1 Labs, we were interested in testing our PHP code, but didn’t want to deal with the overhead and complexity of the current PHP testing frameworks. We thought we could make it simpler. So we created our own PHP test automation framework (FireTest). Along with FireTest, we created a Dependency Injection library (FireDI). When building out FireDI, we decided to add functionality that would allow us to easily mock our dependencies so that that isolating our classes and testing our code would be easy.

A little disclaimer here: As we share our best practices and code examples, we realize that our ideal workflows and best practices might not match with what you feel works best for you. As we have learned, there are multiple ways to code a project. This is what we find works best for us.

Writing Unit Tests with FireTest and FireDI

In this tutorial, we will cover our best practices for using FireTest along with FireDI to write unit tests for our PHP code. If you don’t already have FireTest setup in your project, you can follow our Getting Started Guide to get it setup.

Writing tests for MyClass:

<?php

use \MyDependency;

class MyClass 
{
    private $myDependency;

    public function __construct(MyDependency $myDependency)
    {
        $this->myDependency = $myDependency;
    }

    public function myLogicalFunction()
    {
        if ($this->myDependency->isLogicalToDoSo()) {
            return true;
        }
        return false;
    }
}

As you can see in the MyClass example above, to test the myLogicalFunction(), you will need to create test cases for both when $this->myDependency->isLogicalToDoSo() returns true, and when it returns false.

With FireDI, you’ll be able to mock the MyDependency class.

use \UA1Labs\Fire\Test\TestCase;
use \UA1Labs\Fire\Di;
use \MyClass;

class MyClassTestCase extends TestCase
{
    private fireDi;
    private myClass;

    public function setUp()
    {
        $this->fireDi = new Di();
    }

    public function tearDown()
    {
        unset($this->fireDi);
    }

    public function testMyLogicalFunction()
    {
        $this->fireDi->set('MyDependency', new MyDependencyMock());
        $myDependency = $this->fireDi->get('MyDependency');
        $myClass = $this->fireDi->get('MyClass');

        $this->should('Return true when MyDependency::isLogicalToDoSo() returns true');
        $myDependency->isLogicalToDoSoValue = true;
        $this->assert($myClass->myLogicalFunction() === true);

        $this->should('Return false when MyDependency::isLogicalToDoSo() returns false');
        $myDependency->isLogicalToDoSoValue = false;
        $this->assert($myClass->myLogicalFunction() === false);
    }

}

class MyDependencyMock
{
    public $isLogicalToDoSoValue;

    public function isLogicalToDoSo()
    {
        return $this->isLogicalToDoSoValue;
    }
}

In the test case above, you will see where MyDependency was mocked with MyDependencyMock using $this->fireDi->set('MyDependency', new MyDependencyMock());. We then used FireDI to gain access to the instance of MyDependencyMock so that we could set the variable isLogicalToDoSoValue. This is so when MyClass called the isLogicalToDoSo() method, it would return the desired value of true or false, depending on which test case you were testing for.

Leave a comment

Leave a Reply