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

12 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 :*)

Leave a Reply