3

I have a class like this:

class A {

    private function testing($x)
    {
        // do something
        $this->privateMethod();
    }

    private function privateMethod($number) {
        // do something
    }

}

To invoke testing() I use this:

$reflection = new \ReflectionClass('A');
$method = $reflection->getMethod('testing');
$method->setAccessible(TRUE);

$object = new A();
$parameters = array();
$result = $method->invokeArgs($object, $parameters);

But I don't know how to mock privateMethod(). I want testing only the code in testing() method. I want to point out what I want privateMethod() to return result without actually method to be called.

micobg
  • 1,272
  • 6
  • 21
  • 35
  • I don't think you need to test private methods nor mock one for that matter. You should really be testing the public methods; the ones other classes would rely on. – Czar Pino Oct 17 '14 at 14:13
  • 1
    The point of unit testing is to test your public interface. Your private method should eventually be called somewhere in your code, triggered by a public/protected method. Theoretically if your private method is not working as expected then the calling code (which you are testing) isn't going to work, therefore any asserts you've made should fail. – Crackertastic Oct 17 '14 at 14:18
  • My class includes one public method and about 10 private methods. The public method just call a few of private methods and the work actually is doing by them. The result of any of them depend of the data in databese. How to test these methods? – micobg Oct 17 '14 at 14:37
  • Generally what you would then is mock the database or provide a test database to work with. – Crackertastic Oct 17 '14 at 21:36
  • @Crackertastic What if those private/protected methods were might change the behavior of the tested method, then you must mock them to expect certain value to make the test works, so the private/protected methods will be not covered by the test unit ? – Shakir El Amrani Aug 11 '21 at 23:35
  • @ElAmraniChakir So, in a perfect world, any private/protected methods would be called by the public code being tested and this would handle all of the non-public code being covered. One of the benefits of testing is being able to discover when your non-public code is affecting the outcome of public code. This could be a flaw in the design of the code, a legitimate bug, or maybe even a bad test. Mocking non-public code to go from red to green on the public code isn't the answer though. – Crackertastic Aug 21 '21 at 02:34

1 Answers1

7

If you can change private to protected, you would be able to use partial mocks for this.

$object = $this->getMockBuilder('A')
    ->setMethods(array('privateMethod'))
    ->getMock();
$object->expects($this->any())
    ->method('privateMethod')
    ->will($this->returnValue($x));

This will replace the implementation only on the methods in the setMethods array, and all other methods will execute the original code. This however do not work for private methods, as the mock objects extends the original one; but it can not override the private.

Maxim Krizhanovsky
  • 26,265
  • 5
  • 59
  • 89
  • in case someone comes here looking to find **how to mock private methods in Mockery** - the answer is that Mockery does not support mocking private or protected methods by design: https://github.com/padraic/mockery/issues/30#issuecomment-1742564 – Dimitry K Nov 26 '15 at 11:59
  • it does not work – afeef Apr 07 '20 at 10:03