So, there is a possible way, but let me first clarify some stuff.
You are calling parent::getName(), on a class that is extending nothing. I will assume you just forgot to write extends Parent after class Child.
Assuming the previous stuff, I will write your code again:
class Parent
{
public function getName()
{
return 'Parent';
}
}
class Child extends Parent
{
public function getName(bool $someParameter)
{
return $someParameter ? 'child' : parent::getName();
}
}
To be able to mock this, you have to write this:
$mock = \Mockery::mock(Child::class);
$mock->shouldReceive('getName')
->andReturn('Parent');
// Then do whatever you want to but you will end up calling $mock->getName()
As you said, you are not mocking the Parent class, so you are like "ignoring" the implementation of Chield's getName() method. As you said, that is not exactly good in your case, as you want to test exactly that code, and by mocking it, you are not testing the code but testing that Mockery does what it should do, mock that method and return Parent when you call getName() no matter what the parameter is.
Another solution is to use dependency injection, you can modify the Child class (if your project allows you to) to receive the Parent class like this:
class Parent
{
public function getName()
{
return 'Parent';
}
}
class Child
{
private Parent $parent;
public function __construct(Parent $parent)
{
$this->parent = $parent;
}
public function getName(bool $someParameter)
{
return $someParameter ? 'child' : $this->parent->getName();
}
}
Now the test would be like this:
$mock = \Mockery::mock(Parent::class);
$mock->shouldReceive('getName')
->andReturn('Parent');
$child = new Child($mock);
// Then do whatever you want to but you will end up calling $child->getName()
But this may not help a lot if you want to overwrite stuff, because the baseline Parent has logic that works. So maybe passing it as a dependecy makes no sense and you must extend it.
In that case, you should have something different in Parent, like this:
class AnotherObjectWithLogic
{
public function doSomething(): string
{
return 'Parent';
}
}
class Parent
{
private AnotherObjectWithLogic $logicObject;
public function __construct(AnotherObjectWithLogic $logicObject)
{
$this->object = $logicObject;
}
public function getName(): string
{
return $this->object->doSomething;
}
}
class Child extends Parent
{
public function getName(bool $someParameter): string
{
return $someParameter ? 'child' : parent::getName();
}
}
Now, your test would look like this:
$mock = \Mockery::mock(AnotherObjectWithLogic::class);
$mock->shouldReceive('doSomething')
->andReturn('Parent');
$child = new Child($mock);
// Then do whatever you want to but you will end up calling $child->getName()
This way you can have both classes as pristine as possible, but you only need to pass the object or whatever you are calling to do something when you need to call getName on Parent class.
There is also dependency inversion but it may not be exactly what you are aiming for, nor your issue. But still helps.