class ProtectedPrivatesTest

Same name in other branches
  1. 3.x modules/phpunit_example/tests/src/Unit/ProtectedPrivatesTest.php \Drupal\Tests\phpunit_example\Unit\ProtectedPrivatesTest
  2. 8.x-1.x phpunit_example/tests/src/Unit/ProtectedPrivatesTest.php \Drupal\Tests\phpunit_example\Unit\ProtectedPrivatesTest

ProtectedPrivates unit testing of restricted methods.

This test case demonstrates the following unit testing patterns and topics:

  • Using reflection to test private class methods.
  • Using subclassing to test protected class methods.

If you are reading this and don't understand the basics of unit testing, start reading AddClassTest instead.

This test class uses reflection and subclassing to work around method access problems. Since, by design, a private method is inaccessible, we have to use reflection to gain access to the method for our own purposes.

The getAccessibleMethod() method demonstrates a way to do this.

Once we've set the method to be accessible, we can use it as if it were public.

The same technique can be used for protected methods. However, there might be times when it makes more sense to subclass the class under test, and just make a public accessor method that way. So we demonstrate that here in testProtectedAdd().

@group phpunit_example @group examples

Hierarchy

Expanded class hierarchy of ProtectedPrivatesTest

Related topics

File

modules/phpunit_example/tests/src/Unit/ProtectedPrivatesTest.php, line 41

Namespace

Drupal\Tests\phpunit_example\Unit
View source
class ProtectedPrivatesTest extends UnitTestCase {
    
    /**
     * Get an accessible method using reflection.
     */
    public function getAccessibleMethod($class_name, $method_name) {
        $class = new \ReflectionClass($class_name);
        $method = $class->getMethod($method_name);
        $method->setAccessible(TRUE);
        return $method;
    }
    
    /**
     * Good data provider.
     */
    public static function addDataProvider() {
        return [
            [
                5,
                2,
                3,
            ],
        ];
    }
    
    /**
     * Test ProtectedPrivate::privateAdd().
     *
     * We want to test a private method on a class. This is problematic
     * because, by design, we don't have access to this method. However,
     * we do have a tool available to help us out with this problem:
     * We can override the accessibility of a method using reflection.
     *
     * @dataProvider addDataProvider
     */
    public function testPrivateAdd($expected, $a, $b) {
        // Get a reflected, accessible version of the privateAdd() method.
        $private_method = $this->getAccessibleMethod('Drupal\\phpunit_example\\ProtectedPrivates', 'privateAdd');
        // Create a new ProtectedPrivates object.
        $pp = new ProtectedPrivates();
        // Use the reflection to invoke on the object.
        $sum = $private_method->invokeArgs($pp, [
            $a,
            $b,
        ]);
        // Make an assertion.
        $this->assertEquals($expected, $sum);
    }
    
    /**
     * Bad data provider.
     */
    public static function addBadDataProvider() {
        return [
            [
                'string',
                [],
            ],
        ];
    }
    
    /**
     * Test ProtectedPrivate::privateAdd() with bad data.
     *
     * This is essentially the same test as testPrivateAdd(), but using
     * non-numeric data. This lets us test the exception-throwing ability
     * of this private method.
     *
     * @dataProvider addBadDataProvider
     */
    public function testPrivateAddBadData($a, $b) {
        // Get a reflected, accessible version of the privateAdd() method.
        $private_method = $this->getAccessibleMethod('Drupal\\phpunit_example\\ProtectedPrivates', 'privateAdd');
        // Create a new ProtectedPrivates object.
        $pp = new ProtectedPrivates();
        // Use the reflection to invoke on the object.
        // This should throw an exception.
        $this->expectException(\InvalidArgumentException::class);
        $private_method->invokeArgs($pp, [
            $a,
            $b,
        ]);
    }
    
    /**
     * Test ProtectedPrivates::protectedAdd() using a stub class.
     *
     * We could use the same reflection technique to test protected
     * methods, just like we did with private ones.
     *
     * But sometimes it might make more sense to use a stub class
     * which will have access to the protected method. That's what
     * we'll demonstrate here.
     *
     * @dataProvider addDataProvider
     */
    public function testProtectedAdd($expected, $a, $b) {
        $stub = new ProtectedPrivatesSubclass();
        $this->assertEquals($expected, $stub->subclassProtectedAdd($a, $b));
    }
    
    /**
     * Test ProtectedPrivates::protectedAdd() with bad data using a stub class.
     *
     * This test is similar to testProtectedAdd(), but expects an exception.
     *
     * @dataProvider addBadDataProvider
     */
    public function testProtectedAddBadData($a, $b) {
        $stub = new ProtectedPrivatesSubclass();
        $this->expectException(\InvalidArgumentException::class);
        $stub->subclassProtectedAdd($a, $b);
    }

}

Members

Title Sort descending Deprecated Modifiers Object type Summary Overrides
PhpUnitWarnings::$deprecationWarnings private static property Deprecation warnings from PHPUnit to raise with @trigger_error().
PhpUnitWarnings::addWarning public function Converts PHPUnit deprecation warnings to E_USER_DEPRECATED.
ProtectedPrivatesTest::addBadDataProvider public static function Bad data provider.
ProtectedPrivatesTest::addDataProvider public static function Good data provider.
ProtectedPrivatesTest::getAccessibleMethod public function Get an accessible method using reflection.
ProtectedPrivatesTest::testPrivateAdd public function Test ProtectedPrivate::privateAdd().
ProtectedPrivatesTest::testPrivateAddBadData public function Test ProtectedPrivate::privateAdd() with bad data.
ProtectedPrivatesTest::testProtectedAdd public function Test ProtectedPrivates::protectedAdd() using a stub class.
ProtectedPrivatesTest::testProtectedAddBadData public function Test ProtectedPrivates::protectedAdd() with bad data using a stub class.
RandomGeneratorTrait::getRandomGenerator protected function Gets the random generator for the utility methods.
RandomGeneratorTrait::randomMachineName protected function Generates a unique random string containing letters and numbers.
RandomGeneratorTrait::randomObject public function Generates a random PHP object.
RandomGeneratorTrait::randomString public function Generates a pseudo-random string of ASCII characters of codes 32 to 126.
RandomGeneratorTrait::randomStringValidate Deprecated public function Callback for random string validation.
UnitTestCase::$root protected property The app root. 1
UnitTestCase::getClassResolverStub protected function Returns a stub class resolver.
UnitTestCase::getConfigFactoryStub public function Returns a stub config factory that behaves according to the passed array.
UnitTestCase::getConfigStorageStub public function Returns a stub config storage that returns the supplied configuration.
UnitTestCase::getContainerWithCacheTagsInvalidator protected function Sets up a container with a cache tags invalidator.
UnitTestCase::getStringTranslationStub public function Returns a stub translation manager that just returns the passed string.
UnitTestCase::setUp protected function 358
UnitTestCase::setUpBeforeClass public static function
UnitTestCase::__get public function