TL;DR
While I can't directly address the specific problem mentioned by the original poster (OP), I'd like to offer some thoughts on the matter that could potentially provide valuable insights.
Explanation
When using Mockery's runtime partial test doubles (created with makePartial()), the original constructor of the mocked class isn't invoked. But! objects should be instantiated somehow! If I remember correctly, Mockery achieves this by invoking the parent constructor.
It's worth noting that Laravel's $this->partialMock() method essentially utilizes Mockery's makePartial().
In the situation described by the OP, the absence of an original constructor call leads to an uninitialized $foo property. Consequently, when the getFoo() method is invoked, it attempts to access $this->foo, triggering the "Typed property App\Modules\NoConstructor::$foo must not be accessed before initialization" error.
You can gain further insights from this excellent article.
Possible Solutions
Setting Public Properties
One approach is to set the public properties on a mocked object.
$mockedObject->foo = 'bar';
Unfortunately, this option isn't feasible in the OP's case since foo is private.
Passing Arguments to the Constructor
Another strategy involves passing dependencies to the constructor.
$mockedObject = Mockery::mock(MyClass::class, [app(Dependency::class)])->makePartial();
However, a couple of key points to note are:
- The second argument in the
mock method should be an indexed array, not an associative one. So, use [10] instead of ['foo' => 10].
- Laravel's
$this->mock, $this->partialMock, and $this->spy helpers do not support passing constructor arguments. For this, you need to utilize Mockery::xxx.