PHP Overloading to Unit Test Private Properties and Methods PHP Overloading to Unit Test Private Properties and Methods php php

PHP Overloading to Unit Test Private Properties and Methods


If you find yourself stuck and simply must access a private/protected property to enable thorough testing, at least place the code that enables access in your test or testing framework. Embedding testing-only code in production code a) complicates the design, b) adds more code that must be tested, and c) means the code runs differently in production.

You can use Ken's subclass method for protected properties, but if you need to access private and are on PHP 5.3.2+ you can use reflection.

function test__Construction_Should_Properly_Set_Tables() {    $cv = new CVObject( array( 'tables' => $this->standardTableDef ) );    $tables = self::getPrivate($cv, 'tables');    $this->assertEqual( $tables, $this->standardTableDef );}static function getPrivate($object, $property) {    $reflector = new ReflectionProperty(get_class($object), $property);    $reflector->setAccessible(true);    return $reflector->getValue($object);}

Note that getPrivate() won't work as written for properties inherited from superclasses, but it's not too hard to loop up the hierarchy to find the declaring class.


While testing a component, you have to test only it's interface (input, output, exceptions), without considering or even knowing it's internal implementation (even better if one programmer writes test cases and the other does the implementation, please refer to XP and TDD techniques). So, the only thing you have to test are public methods.

To ensure, that your private (helper) methods are written correctly, simply use code coverage analyzer (please checkout Code Coverage tools for PHP) and cover as much code as possible with your test cases.

Your solution will guarantee you a maintenance nightmare. Test cases and component implementation should not be coupled in any way, because coupling would need to be bulletproof or otherwise you'll have to test it too.


A quick and dirty solution is to use protected (instead of private) methods, and then test using a wrapper that makes the methods under test public.

class Foo{    protected function bar(){} // should really be private but protected will do}class FooTestWrapper extends Foo{    public function bar{} { return parent::bar(); } // this is testable}

But as ljank points out, testing private methods/implementation can become a maintenance nightmare - it probably means you are doing work that should be farmed out to other classes.