Unit testing PHP classes with private or protected methods and properties can be a real challenge. One solution to the problem is to use a public method that calls the protected method or a getter to access the private property, but that may not be desirable in many instances. So how can you unit test private methods and get adequate code coverage without being limited to functional tests of a class’s public api? There is still a way to call those methods or access the value of private properties in unit tests using reflection.

 

Let’s say we have a class Foo with private method bar and property foobar:

class Foo {

		private $foobar;

		private function bar( $number )
		{
			// keep me private!
		}
	}

 

To call a private/protected method in a test, simply use reflection to set the accessibility of the method to public:

 	/**
 	 * testBar
 	 *
 	 * @author	Joe Sexton <joe@webtipblog.com>
 	 */
	public function testBar()
	{
		$number = 1;

		$object = new Foo();
		$reflector = new ReflectionClass( 'Foo' );
		$method = $reflector->getMethod( 'bar' );
		$method->setAccessible( true );

		$result = $method->invokeArgs( $object, array( $number ) );

		$this->assertEquals( 1, $result ); // whatever your assertion is

	}

The first argument of invokeArgs() is an instance of the object, the second argument is an array of parameters to pass to the method.
 

We can make this a little more abstract for re-use elsewhere in our test class:

 	/**
 	 * testBar
 	 *
 	 * @author	Joe Sexton <joe@webtipblog.com>
 	 */
	public function testBar()
	{
		$number = 1;

		$object = new Foo();
		$method = $this->getPrivateMethod( 'Foo', 'bar' );;

		$result = $method->invokeArgs( $object, array( $number ) );

		$this->assertEquals( 1, $result ); // whatever your assertion is

	}

	/**
 	 * getPrivateMethod
 	 *
 	 * @author	Joe Sexton <joe@webtipblog.com>
 	 * @param 	string $className
 	 * @param 	string $methodName
 	 * @return	ReflectionMethod
 	 */
	public function getPrivateMethod( $className, $methodName ) {
		$reflector = new ReflectionClass( $className );
		$method = $reflector->getMethod( $methodName );
		$method->setAccessible( true );

		return $method;
	}

 

To access the value to a private/protected property, you can use reflection to set the accessibility in a similar fashion:

 	/**
 	 * testFoobar
 	 *
 	 * @author	Joe Sexton <joe@webtipblog.com>
 	 */
	public function testFoobar()
	{
		$expectedValue = 1;

		$object = new Foo();
		$property = $this->getPrivateProperty( 'Foo', 'foobar' );

		$this->assertEquals( $property->getValue( $object ), $expectedValue ); // whatever your assertion is
	}

	/**
 	 * getPrivateProperty
 	 *
 	 * @author	Joe Sexton <joe@webtipblog.com>
 	 * @param 	string $className
 	 * @param 	string $propertyName
 	 * @return	ReflectionProperty
 	 */
	public function getPrivateProperty( $className, $propertyName ) {
		$reflector = new ReflectionClass( $className );
		$property = $reflector->getProperty( $propertyName );
		$property->setAccessible( true );

		return $property;
	}

 

Reflection really opens up unit testing to those class internals without making them public so that every unit can be independently tested to find where code ‘breaks down’ as the application evolves.

One comment on “Unit Testing Private Methods and Properties with PHPUnit

  1. Michal Haták says:

    Hi,

    thanks for an article. For private/protected properties you can alsou use PHPUnit_Framework_Assert::readAttribute($classInstance, "propertyName")

Comments are closed.