Best practices to test protected methods with PHPUnit Best practices to test protected methods with PHPUnit php php

Best practices to test protected methods with PHPUnit


If you're using PHP5 (>= 5.3.2) with PHPUnit, you can test your private and protected methods by using reflection to set them to be public prior to running your tests:

protected static function getMethod($name) {  $class = new ReflectionClass('MyClass');  $method = $class->getMethod($name);  $method->setAccessible(true);  return $method;}public function testFoo() {  $foo = self::getMethod('foo');  $obj = new MyClass();  $foo->invokeArgs($obj, array(...));  ...}


You seem to be aware already, but I'll just restate it anyway; It's a bad sign, if you need to test protected methods. The aim of a unit test, is to test the interface of a class, and protected methods are implementation details. That said, there are cases where it makes sense. If you use inheritance, you can see a superclass as providing an interface for the subclass. So here, you would have to test the protected method (But never a private one). The solution to this, is to create a subclass for testing purpose, and use this to expose the methods. Eg.:

class Foo {  protected function stuff() {    // secret stuff, you want to test  }}class SubFoo extends Foo {  public function exposedStuff() {    return $this->stuff();  }}

Note that you can always replace inheritance with composition. When testing code, it's usually a lot easier to deal with code that uses this pattern, so you may want to consider that option.


teastburn has the right approach. Even simpler is to call the method directly and return the answer:

class PHPUnitUtil{  public static function callMethod($obj, $name, array $args) {        $class = new \ReflectionClass($obj);        $method = $class->getMethod($name);        $method->setAccessible(true);        return $method->invokeArgs($obj, $args);    }}

You can call this simply in your tests by:

$returnVal = PHPUnitUtil::callMethod(                $this->object,                '_nameOfProtectedMethod',                 array($arg1, $arg2)             );