loading...
Cover image for Building a PHP Framework: Part 5 - Test Driven Development

Building a PHP Framework: Part 5 - Test Driven Development

mattsparks profile image Matt Sparks ・3 min read

In part 4 we laid the foundation for Analyze. Now it's time to write the very first lines of code!

Before we continue, please allow me to interrupt with a quick announcement: I've started a newsletter! Each week I'll send you a great email filled with updates, great links, tips & tricks, and other non-dev randomness. If you're interested you can sign up by following this link.

What is Test Driven Development?

Let's get the Wikipedia definition out of the way:

Test-driven development (TDD) is a software development process that relies on the repetition of a very short development cycle: requirements are turned into very specific test cases, then the software is improved to pass the new tests, only. This is opposed to software development that allows software to be added that is not proven to meet requirements.

Great. So what does that mean?

Essentially, test driven development is a process of writing tests before writing any code, then writing code that passes the tests.

  1. Write test
  2. Run tests, see new one fail
  3. Write code that passes
  4. Run tests
  5. Refactor

If you're new to TDD, this probably seems pretty weird. Stick with me.

Tools For Test Driven Development

I will be using PHPUnit, a testing framework, to do all of my testing. For instructions on how to install PHPUnit, please see their documentation.

Note: I'm barely touching the surface of what PHPUnit can do in this post. I highly encourage you to read through the documentation.

A Simple Example

Let's say you want to build a class that takes two numbers and adds them. Let's write a test to ensure that our add method returns the correct result. Keep in mind, this example is initially simple to illustrate how PHPUnit works on a basic level.

<?php
use PHPUnit\Framework\TestCase;

class ExampleTest extends TestCase
{
    public function testTwoNumbersAreAdded()
    {
        $adder = new NumberAdder(1, 2);
        $result = $adder->add();

        $this->assertEquals(3, $result);
    }
}

In this test we create a new NumberAdder object, passing the two numbers we want to manipulate (1 and 2). From there we add the numbers together and tell PHPUnit that we expect the result to equal 3. Let's run it:

TDD Example 1

It, of course, fails giving us:

Error: Class 'NumberAdder' not found

Following the TDD method, let's create the class and get rid of that error.

<?php
namespace NumberAdder;

class NumberAdder
{

}

Next, import it into our ExampleTest:

use NumberAdder\NumberAdder;

Now run it again:

TDD Example 2

Nice, the error is gone and we have a new one:

Error: Call to undefined method NumberAdder\NumberAdder::add()

That makes sense, we haven't created it. Let's do that.

<?php
namespace NumberAdder;

class NumberAdder
{
    public $firstNumber;
    public $secondNumber;

    public function __construct(int $firstNumber, int $secondNumber)
    {
        $this->firstNumber = $firstNumber;
        $this->secondNumber = $secondNumber;
    }

    public function add() : int
    {

    }
}

TDD Example 3

Alright, the previous error is gone. Now we get:

Failed asserting that null matches expected 3.

Our add method doesn't return anything, hence the null, and null doesn't equal 3. One last fix:

<?php
namespace NumberAdder;

class NumberAdder
{
    public $firstNumber;
    public $secondNumber;

    public function __construct(int $firstNumber, int $secondNumber)
    {
        $this->firstNumber = $firstNumber;
        $this->secondNumber = $secondNumber;
    }

    public function add() : int
    {
        return $this->firstNumber + $this->secondNumber;
    }
}

TDD Example 4

It passes!

The First Analyze Test

The previous example was a very simplified rundown of the TDD process. Write a test, run, it fails, make it not fail, run again, repeat. I'll be doing that the entire way as I build the Analyze PHP Framework. Here's the first one:

<?php
use PHPUnit\Framework\TestCase;
use Analyze\Application;

class ApplicationTest extends TestCase
{
    public function testApplicationInstanceIsReturned()
    {
        $app = new Application;

        $this->assertInstanceOf(Application::class, $app);
    }
}

We are on our way! Be sure to keep track of the Framework repository.

Originally Posted on DevelopmentMatt.com

Discussion

pic
Editor guide
Collapse
kalpeshbdarji profile image
Kalpesh Darji

Also, writing unit test with arrange, act, assert approach is a good practice. Here's the comprehensive overview of unit testing and TDD: simform.com/unit-testing-tdd/