-
Notifications
You must be signed in to change notification settings - Fork 27
Helpers
This is a tutorial for using https://github.com/etsy/phpunit-extensions/tree/master/PHPUnit/Extensions/Helper.
In a unit test there should be absolutely no control structures.
Unit tests are meant to minimize your debug time by being small to the point tests on small specific pieces of code.
Since unit tests are intended to reduce the time spent debugging, it should make sense that the unit tests themselves should not be subject to debugging.
All logic should be tested. Adding control structures to tests is logic that should to be tested, and things that should be tested are possibly things that you may end up having to debug.
If for some reason you really need logic to accomplish something in your test, it should be pulled out into a well tested helper so that you don't end up debugging your tests in addition to your code.
AccessibleObject
is a wrapper for an object that contains private
or protected
methods that you would like to test.
In general you should never be in a position to do this, but many feel like they should do this terrible dance to test private
methods in isolation:
- See a
private
method you want to test in isolation - Upgrade the
private
method toprotected
- Extend the class in the
TestCase
code file - Override all
protected
(should beprivate
) methods you would like to test in isolation to bepublic
- Test the new child class instead of the actual class
Note: You will not be able to use AccessibleObject to call into private methods involving reference parameters. Until variadics and argument unpacking are unveiled in PHP 5.6, the most reasonable workarounds are (unfortunately) to make the method public within the class, or perhaps more attractively, to factor the method out into the public interface of a new class.
In your production code, annotate any private
and protected
methods that you would like to make accessible for testing with @accessibleForTesting
:
class ObjectWithPrivate {
private function myInaccessiblePrivateMethod() {
return 'inaccessible';
}
/** @accessibleForTesting */
private function myAccessiblePrivateMethod() {
return 'accessible';
}
}
In your test code, simply wrap your object with PHPUnit_Extensions_Helper_AccessibleObject
:
// alias the namespace
use PHPUnit\Extensions\Helper\AccessibleObject;
class ObjectWithPrivateTest extends PHPUnit_Framework_TestCase {
private $accessible;
protected setUp() {
parent::setUp();
$this->accessible = new AccessibleObject(new ObjectWithPrivate());
}
}
Since myInaccessiblePrivateMethod()
is not annotated, it will throw a ReflectionException
when called:
public function testInaccessible() {
$this->expectException(ReflectionException::class);
$this->accessible->myInaccessiblePrivateMethod();
}
Since myAccessiblePrivateMethod()
is annotated, it will be callable as though it were an accessible method call on the original object:
public function testAccessible() {
$this->assertEquals('accessible', $this->accessible->myAccessiblePrivateMethod());
}