How to test PHP code using PHPUnit

PHPUnit automatically executable tests that verify your application’s behavior. Thus – you can ensure that your changes don’t break existing functionality. This post will show you how to test your PHP code using PHPUnit.

You can learn more about coding here. We discuss PHP, Bash, and more.

Setup PHPUnit

You can setup PHPUnit using the following terminal command, after navigating to the project directory:

composer require --dev phpunit/phpunit ^9

As a result, the command will add the requirement of PHPUnit to your composer.json file. Composer will then install the dependencies. With that, you are all set and ready to go!

Note that:

  • PHPUnit should be set up on a per-project basis.
  • PHPUnit should only be used in a development environment.
  • Using PHPUnit on a web-server will result in unwanted behavior.
  • This post uses Composer for the installation of PHPUnit.

Test the PHP code with PHPUnit

PHPUnit allows the user to test multiple use cases in one go. Instead of writing code and using var_dump or print_r to confirm values, you can write a test. PHPUnit tests by asserting the obtained result against the expected result. Don’t worry! We will discuss assertions in more detail.

Example code to test

Consider the following PHP class Password, which checks for the strength of a password.

The method get_strength() is used to evaluate the strength of the password. The method checks for two types of data: alphabetical and numeric. The password strength is determined by the number of data-types it contains. The method returns a score of 1 for weak and 2 for strong. The validate() method checks if the password is greater than eight, and the score is greater than 0. If the validation fails, the InvalidPasswordException is thrown.

<?php
class Password {
    protected $password = "";
    function __construct($password = "")
    {
        $this->password = $password;
    }
    public function validate(){
        if(strlen($this->password) < 8){
            throw new InvalidPasswordException();
        }
        if($this->get_strength() == 0){
            throw new InvalidPasswordException();
        }
    }
    public function get_strength(){
        $strength = 0;
        if(preg_match('/[A-Za-z]/', $this->password)){
            // Letter found!
            $strength +=1;
        }
        if(preg_match('/[0-9]/', $this->password)){
            // Digit found!
            $strength += 1;
        }
        return $strength;
    }
}
class InvalidPasswordException extends Exception{
    public function errorMessage()
    {
       //error message
       $errorMsg = 'Invalid password. Make sure the password length is more than 8 and contains alphanumeric characters.';
       return $errorMsg;
    }
}

Here are some use-cases for the Password class:

  • One data-type password gives a score of 1
  • Two data-types password gives a score of 2
  • Symbols only password (score of 0) throws an exception upon validation
  • A password of length seven or less throws an exception upon validation

One way of testing the possible use cases for the Password class is by printing and comparing each and every use-case. PHPUnit provides a more robust method for testing. Let us begin by making a file PasswordTest.php.

Example tests

PHPUnit has some conventions which the framework uses for testing:

  • Tests for class ClassName go by ClassNameTest, i.e. it begins with the class name and ends with Test.
  • The test classes inherit PHPUnit/Framework/TestCase. This allows the test classes to use PHPUnit methods like assertions.
  • Each test inside the class is a public function. The name of the function begins with test*.

These functions will use assertions to test the code. A failed assertion fails the test. One test may have several assertions, e.g. In Password class test case 1, you will need to assert each of the two data-types one by one to confirm that one data-type password gives the score 1. Hence one test will have multiple assertions.

The class PasswordTest tests each of the 4 test cases for Password class one by one. Each of the use cases is tested separately. Each function in the class tests for one of the use-cases. Another convention is that the name of the function (camel-cased words followed by the word test*) is also a short description of what the test does.

<?php
// Loading up TestCase
use PHPUnit\Framework\TestCase;

require "Password.php";

class PasswordTest extends TestCase{

    public function testOneDatatypePasswordGivesScoreOf1(){
        $pass = new Password("Foopassword");
        $strength = $pass->get_strength();

        // Asserting that strength is 1
        $this->assertEquals(1, $strength);

        $pass = new Password("123123123");
        $strength = $pass->get_strength();

        // Asserting that strength is 1
        $this->assertEquals(1, $strength);
    }
    public function testTwoDatatypePasswordGivesScoreOf2(){
        $pass = new Password("Foobar123");
        $strength = $pass->get_strength();

        // Asserting that strength is 1
        $this->assertEquals(2, $strength);
    }
    public function testScoreOf0ThrowsException()
    {
        // Declaring an Exception is expected in the below code
        $this->expectException(InvalidPasswordException::class);
        $pass = new Password("#!#!#!!#!#!");
        $pass->validate();
    }
    public function testPasswordLengthLessThan8ThrowsException()
    {
        // Declaring an Exception is expected in the below code
        $this->expectException(InvalidPasswordException::class);
        $pass = new Password("foo");
        $pass->validate();
    }
}

For testing, we use assert* methods. For exceptions, we can use expectExeption (Exception::class) to test whether the code correctly throws an exception.

Testing your PHP code

Testing is quite simple with PHPUnit. You simply need to run the following command from your project directory:

./vendor/bin/PHPUnit PasswordTest.php

If all tests succeed, the following output will be given:

Another way is to test using the function names as short descriptions for each test:

./vendor/bin/PHPUnit --testdox PasswordTest.php

PHPUnit can also be used to test all test files in a directory using the following command:

./vendor/bin/PHPUnit

Or:

./vendor/bin/PHPUnit --testdox

The output will be very similar to the above.

Summary

PHPUnit is a robust PHP testing framework. PHPUnit requires a *Test.php file containing a *Test class. The class must extend PHPUnit\Framework\TestCase class (most of the times required). Testing can then be performed. This post gives a very basic usage of PHPUnit. But it can be used for much more!

Some helpful links:

Leave a Reply

Your email address will not be published. Required fields are marked *