Unit Testing PHP with PHPUnit

For a background on Unit Testing in general, check out the post on Unit Testing Overview.

Example PHPUnit Tests

If you have installed PHPUnit and want to take it for a spin, here's an example of how a basic PHPUnit test would look.

For this example, we will be creating a small piece of code for a personal trainer program called TrainerApp. We will create a helper class called FitnessLevelHelper that the app can use to calculate a person's fitness levels for their Body Mass Index (BMI) and their Body Fat Percentage (BFP).

We will first write the test and the placeholder class and methods that will be needed to implement this functionality.

./test/FitnessLevelHelperTest.php

<?php

use TrainerApp\FitnessLevelHelper;

class FitnessLevelHelperTest extends PHPUnit_Framework_TestCase  
{
    public function testCanCalculateBMI()
    {
        $height = 1.575;
        $weight = 56.25;
        $bmi = FitnessLevelHelper::calculateBMI($height, $weight);
        $this->assertEquals(23, $bmi);
    }

    public function testCanCalculateBFP()
    {
        $height = 1.575;
        $weight = 56.25;
        $age = 27;
        $gender = 0;
        $bfp = FitnessLevelHelper::calculateBFP($height, $weight, $gender, $age);
        $this->assertEquals(28.41, $bfp);
    }
}

./src/TrainerApp/FitnessLevelHelper.php

<?php

namespace TrainerApp {

    class FitnessLevelHelper {

        /**
         * @param int $height A person's height in centimeters
         * @param int $weight A person's weight in kilograms
         * @return int
         */
        public static function calculateBMI($height, $weight){}

        /**
         * @param int $height
         * @param int $weight
         * @param boolean $gender Female = 0, Male = 1
         * @param int $age
         * @return float
         */
        public static function calculateBFP($height, $weight, $gender, $age){}
    }
}

When we run the test in PHPUnit, we should get failures because we haven't implemented any logic in the FitnessLevelHelper class methods.

$ phpunit --bootstrap ./src/autoload.php ./test/FitnessLevelHelperTest.php 
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.

FF

Time: 57 ms, Memory: 4.00Mb

There were 2 failures:

1) FitnessLevelHelperTest::testCanCalculateBMI  
Failed asserting that null matches expected 23.

./test/FitnessLevelHelperTest.php:12

2) FitnessLevelHelperTest::testCanCalculateBFP  
Failed asserting that null matches expected 28.41.

./test/FitnessLevelHelperTest.php:22

FAILURES!  
Tests: 2, Assertions: 2, Failures: 2.

Now we need to update the FitnessLevelHelper class and implement the logic to calculate these results:

./src/TrainerApp/FitnessLevelHelper.php

<?php

namespace TrainerApp {

    class FitnessLevelHelper {

        /**
         * @param int $height A person's height in centimeters
         * @param int $weight A person's weight in kilograms
         * @return int
         */
        public static function calculateBMI($height, $weight)
        {
            return ((int) (round($weight / ($height * $height), 0)));
        }

        /**
         * @param int $height
         * @param int $weight
         * @param boolean $gender Female = 0, Male = 1
         * @param int $age
         * @return float
         */
        public static function calculateBFP($height, $weight, $gender, $age)
        {
            $bmi = self::calculateBMI($height, $weight);
            return ( round( ((1.2 * $bmi) + (.23 * $age) - (10.8 * $gender) - 5.4) , 2) );
        }
    }
}

Now when we run the test, we see that they pass.

$phpunit --bootstrap ./src/autoload.php ./test/FitnessLevelHelperTest.php 
PHPUnit 4.8.6 by Sebastian Bergmann and contributors.

..

Time: 114 ms, Memory: 4.00Mb

OK (2 tests, 2 assertions)