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 = &lt;&lt;<class>
            class $proxyClassName extends $superClassName
            {
                public function __call($function, $args)
                {
                    $function = str_replace('protected_', '_',
$function);
                    return call_user_func_array(array(&amp;$this,
$function),  $args);
                }
            }
CLASS;
        eval($class);
    }
 
    if (!empty($params)) {
        // Create an instance using Reflection, because constructor has parameters
        $class = new ReflectionClass($proxyClassName);
        $instance = $class-&gt;newInstanceArgs($params);
    }
    else {
        $instance = new $proxyClassName();
    }
    return $instance;
}
</class>

Example:

1
2
3
$oClass = getProxy( 'myClass', array( 'some params'));
$oClass-&gt;protected_myProtectedFcuntion();
...

Comments

13 Responses to “Testing protected Methods in Unit Tests”

  1. dodger on November 16th, 2007 3:21 pm

    Grmbl - don’t mind the converted > please - this wordpress editor is somehow a bit strange.

  2. Tomas Liubinas on November 16th, 2007 3:26 pm

    What else you can do is adding

    return parent::__call($function, $args)

    for calling possibly already existing __call() method in $superClassName.

  3. MaFi on November 16th, 2007 5:37 pm

    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;
    }

  4. WildKid on November 27th, 2007 1:28 pm

    Really good and really interesting post. I expect (and other readers maybe :)) new useful posts from you!
    Good luck and successes in blogging!

  5. Joe Weber on December 18th, 2007 9:55 pm

    Dig the blog a LOT!
    Nice style and I like the way you discuss the problems . I’m going to book mark it.
    ;)

  6. Dan Peade on April 2nd, 2008 11:13 am

    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 =

  7. Dan Peade on April 2nd, 2008 11:14 am

    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.

  8. Dan Peade on April 2nd, 2008 11:15 am

    Apologies: “…that MaFi showed in her/his post..”

  9. dodger on April 3rd, 2008 1:41 pm

    “his” Post is correct Dan ;)

  10. Taras on July 29th, 2008 5:57 pm

    Hi guys,

    What is the <<<class syntax, and how does it work? I tried to google it, but nothing came up :?

  11. dodger on July 30th, 2008 9:17 am
  12. Taras on August 22nd, 2008 1:41 pm

    great! thanks! I wasn’t aware of that syntax :*)

  13. Anatoliy Belsky on September 17th, 2009 11:17 pm

    Making PHP non public class/object methods available…

    Anyone who did unit testing in PHP knows that private methods are untestable. One workaround for this could be to make no private but protected only members and call them using a proxy class. Another approach I’d like to present here is a small extens…

Leave a Reply