I've been reading here a few questions regarding the use of unit testing to test private methods and properties. I'm new to unit testing and would like input on the method I'm trying so that my testing can access private/protected properties and methods.
In the test I was working on I wanted to confirm that passing a particular parameter to the object resulted in a property being set. I'm using SimpleTest for my unit testing education and my test method is as follows:
function test__Construction_Should_Properly_Set_Tables() {
$cv = new CVObject( array( 'tables' => $this->standardTableDef ) );
$tables = $cv->tables;
$this->assertEqual( $tables, $this->standardTableDef );
}
Then I wrote a __get method in CVObject as follows:
function __get( $name ) {
$trace = debug_backtrace();
$caller = $trace[1];
$inTesting = preg_match( '/simpletest/', $caller['file'] );
if ( $inTesting ) {
return $this->$name;
} else {
trigger_error( 'Cannot access protected property CVObject::$' .
$name . ' in ' . $trace[0]['file'] . ' on line ' .
$trace[0]['line'],
E_USER_NOTICE );
}
}
My idea in this is that if the calling file is from SimpleTest, go ahead and make the property available for the testing purposes, but if not, trigger the error. This allows me to keep the property private but be able to use it in testing, which is going to be more important to me with a particular private method I'm about to begin writing.
So, my question is, am I missing something really bad here and should avoid this technique?
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.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With