18

Is it possible to mock a protected property with PHP Mockery?

I got a class with a method, I will call it `a, that does some magic on an array that is retrieved from a protected property from the same class.

That protected property is filled by another method b, in the same class.

I would like to test method a by mocking the protected property so I don't have to class method b first.

So is this possible? If not, should I refactor my code? Or are there other ways (considering best practises).

Ilyes512
  • 2,627
  • 5
  • 23
  • 27
  • 2
    try using reflection – ArtisticPhoenix Aug 13 '15 at 03:00
  • 1
    I did (of course) google and that was indeed the first thing that came up. But it feels a bit of "hackery". I also wonder how I can mix this with an partial mock. – Ilyes512 Aug 13 '15 at 03:44
  • 1
    If it feels hackery then refactor you code. I am not entirely sure what you want to do but reflection is generally the way to dynamically read class properties when you don't know what they are. – ArtisticPhoenix Aug 13 '15 at 03:47
  • If you wan mock private or protected method that seems your code went bad way, try to refactor it. – Piotr Olaszewski Aug 13 '15 at 06:21
  • Possible duplicate of [phpunit - mockbuilder - set mock object internal property](https://stackoverflow.com/questions/18558183/phpunit-mockbuilder-set-mock-object-internal-property) – Mike B Jul 29 '19 at 20:55

2 Answers2

21

It is possible to mock protected methods, but as some people have pointed out you might want to refactor your code if you feel the need for mocking these methods.

If you do want to mock protected methods you can do this according to the example below:

$myMock = Mockery::mock('myClass')->shouldAllowMockingProtectedMethods();

Using this mock it's then possible to mock protected methods in the same way as you would mock public methods.

Fredrik Schöld
  • 1,588
  • 13
  • 20
8

Sometimes your code is fine and you think there is no reason to change your code to facilitate tests (which is a good reason in my opinion), What I do is to use reflection within my object, you can even have a helper method like this:

class MockingHelpers
{
    public static function mockProperty($object, string $propertyName, $value)
    {
        $reflectionClass = new \ReflectionClass($object);

        $property = $reflectionClass->getProperty($propertyName);
        $property->setAccessible(true);
        $property->setValue($object, $value);
        $property->setAccessible(false);
    }
}

Note the accessible is only applied in the reflection context, thus no damage is done.

It's not the perfect solution, sometimes you might really have an issue in your code, but this could help you!

Renato Mefi
  • 2,131
  • 1
  • 18
  • 27