Requires: PHP 5.3.2 or greater.
If you’re not running 5.3.2+ you can test private methods indirectly by creating a public method, that calls your private method.

Problem

We have a class, StatFinder which contains a private method, getDomainFromEmail() that we want to test.

<?php
class StatFinder
{
    // Get domain from email address
    private function getDomainFromEmail($email='')
    {
        if ($email == '') return '';
        $parts = explode('@', $email);
        if ($parts === false || !isset($parts[1])) return '';

        return $parts[1];
    }
}

We create a test to check that calling getEmailFromDomain(‘iliketurtles@gmail.com’) returns the expected ‘gmail.com‘. I’m using PHPUnit to run the unit test.

<?php
include('../libraries/StatFinder.php');

class StatFinderTest extends PHPUnit_Framework_TestCase
{
    public function testGetDomainFromEmail()
    {
        $sf = new StatFinder();
        $email = 'iliketurtles@gmail.com';
        $expected = 'gmail.com';
        $this->assertEquals($expected, $sf->getDomainFromEmail($email));
    }
}

When run, the test fails because the method is private, so only accessible by the class that defined it.


Failed unit test – (PHPUnit running in PhpStorm)

Solution

You can test private and protected methods by using the ReflectionMethod class, part of the Reflection API that comes with PHP 5.
The setAccessible method of the ReflectionMethod class is only available from PHP 5.3.2 up so you’ll have to be running at least this to use this.

<?php
include('../libraries/StatFinder.php');

class StatFinderTest extends PHPUnit_Framework_TestCase
{
    public function testGetDomainFromEmail()
    {
        $method = new ReflectionMethod('StatFinder', 'getDomainFromEmail');
        $method->setAccessible(true);

        $email = 'iliketurtles@gmail.com';
        $expected = 'gmail.com';
        $this->assertEquals($expected, $method->invoke(new StatFinder, $email));
    }
}

Explanation

<?php
$method = new ReflectionMethod('StatFinder', 'getDomainFromEmail');

This creates an instance of the ReflectionMethod class.
The first argument, StatFinder is the class that contains the private method to test.
The second argument, getDomainFromEmail is the method to test.

<?php
$method->setAccessible(true);

setAccessible(true) allows the private method, getDomainFromEmail to be called from inside the test.

<?php
$this->assertEquals($expected, $method->invoke(new StatFinder, $email));

invoke() invokes the private method.
The first argument, new StatFinder is the object to invoke the method on. For static methods, pass null.
The second argument, $email is the argument to pass to the method. Zero or more arguments can be passed to the method this way.

We run our updated test and it now works.


Successful test

Related