Michael Pawlowsky
Michael Pawlowsky

Reputation: 172

How can I test that a method is private using PHPUnit

Using PHPUnit, I would like to test that a Class CANNOT be instantiated using the __construct [ new Class(); ] method as well as cannot be cloned, woken up etc.

Basically it is a Singleton class, and the __construct, __clone and __wakeup methods set to private to make sure it remains a Singleton.

But how can I test for that?

Upvotes: 1

Views: 148

Answers (3)

Michael Pawlowsky
Michael Pawlowsky

Reputation: 536

All of these are working perfectly.

function testCannotCallConstructor()
{
    try {
        $log = new Log();
        $this->fail('Should never be called!');
    } catch (\Throwable $e) {
        $this->assertNotEmpty($e->getMessage());
    }

    //alternative:
    $this->expectException(\Error::class);
    $log = new Log();
}



public function testConstructPrivate(){
    $method = new \ReflectionMethod('\\Core\\Log', '__construct');
    $result = $method->isPrivate();
    $this->assertTrue( $result, "Log __construct is not private. Singleton not guaranteed.");
}

Thank you very much. I think the one I prefer is the expectException method.

Upvotes: 0

Timurib
Timurib

Reputation: 2743

By design, unit test usually checks a behavior, not an interface (method signature is a part of the interface).

But if you really need that you can use the Reflection API. Check the class hasMethod() and this method isPrivate().

In the PHP7 enviroment you can use try/catch solution proposed by John Joseph, but i recommend to intercept only Error exceptions (Throwable covers all possible erros, not only visibility violation). Also PHPUnit has a @expectedException annotation, it's better than manual try/catch.

Upvotes: 1

John Joseph
John Joseph

Reputation: 951

You can do this by catching the exception thrown by trying to instantiate a new object from the singleton.

Try the following (PHP 7):

class Single
{
    private function __construct() {}
}

class SingleTest extends \PHPUnit_Framework_TestCase
{
    function testCannotCallConstructor()
    {
        try {
            $single = new Single();
            $this->fail('Should never be called!');
        } catch (\Throwable $e) {
            $this->assertNotEmpty($e->getMessage());
        }

        //alternative:
        $this->expectException(\Error::class);
        $single = new Single();
    }
}

Upvotes: 2

Related Questions