Testing protected Methods in Unit Tests
As a followup to my talks on the IPC 07 in Frankfurt here the improved version including:
- support for parameter in constrcutors ( via reflection )
- small bug fix avoiding autoload to conflict
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 | /** * Create proxy of given class. Proxy allows to test of protected class methods * @param string $superClassName * @param array|null $constructorParams parameters for contructor * @return object */ function getProxy($superClassName, array $params = null) { $proxyClassName = "{$superClassName}Proxy"; if (!class_exists($proxyClassName, false)) { $class = <<<class> class $proxyClassName extends $superClassName { public function __call($function, $args) { $function = str_replace('protected_', '_', $function); return call_user_func_array(array(&$this, $function), $args); } } CLASS; eval($class); } if (!empty($params)) { // Create an instance using Reflection, because constructor has parameters $class = new ReflectionClass($proxyClassName); $instance = $class->newInstanceArgs($params); } else { $instance = new $proxyClassName(); } return $instance; } </class> |
Example:
1 2 3 | $oClass = getProxy( 'myClass', array( 'some params')); $oClass->protected_myProtectedFcuntion(); ... |
November 16, 2007 | Filed Under PHP related
Comments
12 Responses to “Testing protected Methods in Unit Tests”
Leave a Reply
Grmbl - don’t mind the converted > please - this wordpress editor is somehow a bit strange.
What else you can do is adding
return parent::__call($function, $args)
for calling possibly already existing __call() method in $superClassName.
hi nice and useful piece of code!
I see one small problem that call_user_func_array only returns false on error (method does not exist). This is hard to debug (e.g. phpunit just stops without a message). So I added an exception Additionally I added getter and setters for non public vars which can be useful as well for unit test.
To code inside the proxy class:
public function __call(\$function, \$args)
{
\$function = str_replace(’UNIT’, ‘_’, \$function);
if(method_exists(\$this,\$function)){
return call_user_func_array(array(&\$this, \$function), \$args);
}else{
throw new Exception(’Method ‘.\$function.’ in class ‘.get_class(\$this).’ does not exist’);
}
}
public function setNonPublicVar(\$name, \$value)
{
\$this->\$name = \$value;
}
public function getNonPublicVar(\$name)
{
return \$this->\$name;
}
Really good and really interesting post. I expect (and other readers maybe :)) new useful posts from you!
Good luck and successes in blogging!
Dig the blog a LOT!

Nice style and I like the way you discuss the problems . I’m going to book mark it.
Yes very cool, thanks a lot.
I didn’t understand the reason for the (my ignorance not your fault at all) on line 38 so I just removed it and went with the text book heredoc notation $class =
lt&;lt&;lt&;CLASS and then ended with CLASS (totally left justified of course).
Probably as a result (though not entirely sure) I needed to put in the back slashes in the eval’d code like MaFi showed in his post.
I also modified str_replace so the replace string was an empty string (ie, protected_myToString becomes just myToString).
Then just called getProxy in my PHPUnit setUp() method and added in the protected_ prefix to calls to protected functions and PHPUnit worked well.
Thanks Frontalaufprall and MaFi really handy work.
Apologies: “…that MaFi showed in her/his post..”
“his” Post is correct Dan
Hi guys,
What is the <<<class syntax, and how does it work? I tried to google it, but nothing came up
See this:
http://de.php.net/manual/en/language.types.string.php#language.types.string.syntax.heredoc
http://de.php.net/manual/en/language.types.string.php#language.types.string.syntax.nowdoc
great! thanks! I wasn’t aware of that syntax :*)