Let’s say we have a class Foo with private method bar and property foobar:
|
class Foo {
private $foobar;
private function bar( $number )
{
// keep me private!
}
}
|
To call a private/protected method in a test, simply use reflection to set the accessibility of the method to public:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
|
/**
* testBar
*
* @author Joe Sexton <joe@webtipblog.com>
*/
public function testBar()
{
$number = 1;
$object = new Foo();
$reflector = new ReflectionClass( 'Foo' );
$method = $reflector->getMethod( 'bar' );
$method->setAccessible( true );
$result = $method->invokeArgs( $object, array( $number ) );
$this->assertEquals( 1, $result ); // whatever your assertion is
}
|
The first argument of invokeArgs() is an instance of the object, the second argument is an array of parameters to pass to the method.
We can make this a little more abstract for re-use elsewhere in our test class:
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
|
/**
* testBar
*
* @author Joe Sexton <joe@webtipblog.com>
*/
public function testBar()
{
$number = 1;
$object = new Foo();
$method = $this->getPrivateMethod( 'Foo', 'bar' );;
$result = $method->invokeArgs( $object, array( $number ) );
$this->assertEquals( 1, $result ); // whatever your assertion is
}
/**
* getPrivateMethod
*
* @author Joe Sexton <joe@webtipblog.com>
* @param string $className
* @param string $methodName
* @return ReflectionMethod
*/
public function getPrivateMethod( $className, $methodName ) {
$reflector = new ReflectionClass( $className );
$method = $reflector->getMethod( $methodName );
$method->setAccessible( true );
return $method;
}
|
To access the value to a private/protected property, you can use reflection to set the accessibility in a similar fashion:
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
|
/**
* testFoobar
*
* @author Joe Sexton <joe@webtipblog.com>
*/
public function testFoobar()
{
$expectedValue = 1;
$object = new Foo();
$property = $this->getPrivateProperty( 'Foo', 'foobar' );
$this->assertEquals( $property->getValue( $object ), $expectedValue ); // whatever your assertion is
}
/**
* getPrivateProperty
*
* @author Joe Sexton <joe@webtipblog.com>
* @param string $className
* @param string $propertyName
* @return ReflectionProperty
*/
public function getPrivateProperty( $className, $propertyName ) {
$reflector = new ReflectionClass( $className );
$property = $reflector->getProperty( $propertyName );
$property->setAccessible( true );
return $property;
}
|
Reflection really opens up unit testing to those class internals without making them public so that every unit can be independently tested to find where code ‘breaks down’ as the application evolves.
For private/protected properties you can alsou use PHPUnit_Framework_Assert::readAttribute($classInstance, "propertyName")
0 comments:
Post a Comment