New testing wrapper to circumvent object access
authorAdam Roses Wight <awight@wikimedia.org>
Fri, 27 Feb 2015 17:22:16 +0000 (09:22 -0800)
committerAdam Roses Wight <awight@wikimedia.org>
Tue, 17 Mar 2015 06:58:36 +0000 (23:58 -0700)
The new TestingAccessWrapper class provides a convenient way to make
all of an object's methods and properties public.

TODO: We should organize test helpers into a source directory.  Note that the
helper and its test are in the same directory.

Change-Id: I958d55df18c74e9d2b25d98cd0316989a0fbbe6f

tests/TestsAutoLoader.php
tests/phpunit/data/helpers/WellProtectedClass.php [new file with mode: 0644]
tests/phpunit/includes/TestingAccessWrapper.php [new file with mode: 0644]
tests/phpunit/includes/TestingAccessWrapperTest.php [new file with mode: 0644]

index b410898..b0f29d5 100644 (file)
@@ -47,6 +47,9 @@ $wgAutoloadClasses += array(
        'TestUser' => "$testDir/phpunit/includes/TestUser.php",
        'LessFileCompilationTest' => "$testDir/phpunit/LessFileCompilationTest.php",
 
+       # tests/phpunit/includes
+       'TestingAccessWrapper' => "$testDir/phpunit/includes/TestingAccessWrapper.php",
+
        # tests/phpunit/includes/api
        'ApiFormatTestBase' => "$testDir/phpunit/includes/api/format/ApiFormatTestBase.php",
        'ApiQueryTestBase' => "$testDir/phpunit/includes/api/query/ApiQueryTestBase.php",
diff --git a/tests/phpunit/data/helpers/WellProtectedClass.php b/tests/phpunit/data/helpers/WellProtectedClass.php
new file mode 100644 (file)
index 0000000..7114cc9
--- /dev/null
@@ -0,0 +1,17 @@
+<?php
+
+class WellProtectedClass {
+       protected $property;
+
+       public function __construct() {
+               $this->property = 1;
+       }
+
+       protected function incrementPropertyValue() {
+               $this->property++;
+       }
+
+       public function getProperty() {
+               return $this->property;
+       }
+}
diff --git a/tests/phpunit/includes/TestingAccessWrapper.php b/tests/phpunit/includes/TestingAccessWrapper.php
new file mode 100644 (file)
index 0000000..d4ad363
--- /dev/null
@@ -0,0 +1,50 @@
+<?php
+/**
+ * Circumvent access restrictions on object internals
+ *
+ * This can be helpful for writing tests that can probe object internals,
+ * without having to modify the class under test to accomodate.
+ *
+ * Wrap an object with private methods as follows:
+ *    $title = TestingAccessWrapper::newFromObject( Title::newFromDBkey( $key ) );
+ *
+ * You can access private and protected instance methods and variables:
+ *    $formatter = $title->getTitleFormatter();
+ *
+ * TODO:
+ * - Provide access to static methods and properties.
+ * - Organize other helper classes in tests/testHelpers.inc into a directory.
+ */
+class TestingAccessWrapper {
+       public $object;
+
+       /**
+        * Return the same object, without access restrictions.
+        */
+       public static function newFromObject( $object ) {
+               $wrapper = new TestingAccessWrapper();
+               $wrapper->object = $object;
+               return $wrapper;
+       }
+
+       public function __call( $method, $args ) {
+               $classReflection = new ReflectionClass( $this->object );
+               $methodReflection = $classReflection->getMethod( $method );
+               $methodReflection->setAccessible( true );
+               return $methodReflection->invoke( $this->object, $args );
+       }
+
+       public function __set( $name, $value ) {
+               $classReflection = new ReflectionClass( $this->object );
+               $propertyReflection = $classReflection->getProperty( $name );
+               $propertyReflection->setAccessible( true );
+               $propertyReflection->setValue( $this->object, $value );
+       }
+
+       public function __get( $name ) {
+               $classReflection = new ReflectionClass( $this->object );
+               $propertyReflection = $classReflection->getProperty( $name );
+               $propertyReflection->setAccessible( true );
+               return $propertyReflection->getValue( $this->object );
+       }
+}
diff --git a/tests/phpunit/includes/TestingAccessWrapperTest.php b/tests/phpunit/includes/TestingAccessWrapperTest.php
new file mode 100644 (file)
index 0000000..8da8e42
--- /dev/null
@@ -0,0 +1,30 @@
+<?php
+
+class TestingAccessWrapperTest extends MediaWikiTestCase {
+       protected $raw;
+       protected $wrapped;
+
+       function setUp() {
+               parent::setUp();
+
+               require_once __DIR__ . '/../data/helpers/WellProtectedClass.php';
+               $this->raw = new WellProtectedClass();
+               $this->wrapped = TestingAccessWrapper::newFromObject( $this->raw );
+       }
+
+       function testGetProperty() {
+               $this->assertSame( 1, $this->wrapped->property );
+       }
+
+       function testSetProperty() {
+               $this->wrapped->property = 10;
+               $this->assertSame( 10, $this->wrapped->property );
+               $this->assertSame( 10, $this->raw->getProperty() );
+       }
+
+       function testCallMethod() {
+               $this->wrapped->incrementPropertyValue();
+               $this->assertSame( 2, $this->wrapped->property );
+               $this->assertSame( 2, $this->raw->getProperty() );
+       }
+}