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.
Williams
Thank you for sharing the information. I am currently doing my final year project and I have chosen PHP for doing the project. Using this private method will be more helpful to me while proceeding with the project. Keep updating.
Scam OmniTech Support
phpunit
Great post. Recently i implement phpunit on symfony2 usring phpstorm and i enjoy it. I think that TDD should be the future of software develop.
Johnny
Thank you, it’s perfect !
Max
Good article.
Fox
Anyone who is using PHP 5.4 and up, there is actually an alternative method to that of reflection:
https://ocramius.github.io/blog/accessing-private-php-class-members-without-reflection/