Wim Pruiksma
Wim Pruiksma

Reputation: 598

Tell phpunit to call public instead of private

My Question is. I have a class i want to test (myClass). In myClass there is a function wich calls a private function thats also in the myClass.

I know i can't test private functions. Is it possible to tell phpunit to call another function instead of the private?

Example

$this->testclass is now the class i want to test

$this->testclass = new \stdClass();
$this->testclass->mock = $this->getMockBuilder('myClass')->getMock();

Outside my testcase i have created a fake class.

$this->mockextended = new \stdClass();
$this->mockextended->mock = new MOCKEXTENDEDCLASSES();

in the $this->mockextended i have a public function.

the function i want to test

public function TestMe(){
$this->somePrivateFunctioniHate(); <==== this is the pain in my ass
}

and the private function

private function somePrivateFunctioniHate(){
   //come code
    }

What i want to do is. the function TestMe is calling a private function. Is it possible to tell phpunit to override the private function and call another function thats inside $this->mockextended; I have tried it like this.

$this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction()

only this gives me a nice error. I did this before and it worked. Called it like this

EDIT For people who don't understand my question. I have another function that calls another class. I din't want to have another class in my test so i created a fake Class outside my testcase. Inserted the same functions as the class the function wants to include. Did it like this

  $this->testclass->chunks = new \stdClass();
    //MOCKchunckTpl is the fake class outside my testcase
            $this->testclass->chunks->config = new MOCKchunkTpl(); 

This works. Whenever a function wants to call $this->testclass->chunks->config->Somefunction(); it will be redirected to my fake class.

BUT when i try to do the same with a function thats calling a private function. Like $this->testclass->somePrivateFunctioniHate() = $this->mockextended->theWholeNewPrivateFunction() it gives a nice error

Fatal error: Can't use method return value in write context in

Upvotes: 0

Views: 58

Answers (1)

StoryTeller
StoryTeller

Reputation: 1748

Short answer: No, there isn't. There is no way for PHPUnit to manipulate private methods.

Mocks are for faking the behavior of classes, which depend on the class you want to test. If you need to overwrite a private method, there is something wrong in your architecture. Private methods should be tested by simple testing the public methods in which they are used. If you need to test it separately, declare it public.

EDIT: Here is an example how you'd test a simple code using a private method or putting this private method in another class:

1. Private method

class MyClass {

    public function myMethod() {
        return $this->myPrivateMethod();
    }

    private function myPrivateMethod() {
        return 2;
    }

}

And the test class:

class MyClassTest extends \PHPUnit_Framework_TestCase {

    public function testMyMethod() {
        $myClass = new MyClass();
        // don't mind the private method, just test if the public method is working
        $this->assertEquals(2, $myClass->myMethod());
    }

}

1. Second class

class MyClass {

    public $dependentClass;

    public function myMethod() {
        return $this->dependentClass->dependentMethod();
    }

}

And the dependent class:

class DependentClass {

    public function dependentMethod() {
        return 38943;
    }

}

Testing MyClass with the DependentClass:

class MyClassTest extends \PHPUnit_Framework_TestCase {

    public function testMyMethod() {
        $dependentMock = $this->getMockBuilder("DependentClass")->getMock();
        $dependentMock->expects($this->any())
            ->method("dependentMethod")
            ->willReturn($this->returnValue(2));

        $myClass = new MyClass();
        $myClass->dependentClass = $dependentMock;

        $this->assertEquals(2, $myClass->myMethod());
    }

Although we defined a whole other return in DependentClass, the test will still pass, because we mocked it and are able to define every behavior we'd expect DependentClass to have.

But to cleanly test the project, we need to define another test for DependentClass as well to test, if this class is working. This test should fail if it is not working anymore, not the test for MyClass.

Upvotes: 2

Related Questions