Partial mocks don't run constructors

At least by default...

Joel Clermont
Joel Clermont

I was pairing with someone recently on a Get Unstuck session, and the developer needed to partially mock a class.

A partial mock lets you mock specific methods on a class, but allows the class to otherwise work as it normally would. This can be a useful testing technique.

And Laravel, helpful as always, provides a helper on the base TestCase to create partial mocks:

// inside your test method
$mock = $this->partialMock(MyClass::class, function (MockInterface $mock) {
    $mock->shouldReceive('methodToMock')->andReturn('some mocked result');

One thing the docs don't mention is that a partial mock created this way will not run the constructor of the class being mocked.

This can be confusing at first, because you might assume the constructor would run as normal. Our intention is only to mock one or two specific methods, after all.

The underlying Mockery library made the decision that you don't want the constructor to be called, even for a partial mock, because it might have some unintended side effects. So this is the default behavior for partial mocks, and this is what the Laravel test helper does.

But if you really need the constructor to run, you can accomplish this by using a different array-based syntax:

// inside your test method
$mock = Mockery::mock(MyClass::class . '[methodToMock]');

Mockery calls this a "partial test double" and refers to the other default kind of partial mock as a "runtime partial double".

There is no Laravel test helper to generate this. If you need your constructor to run on a partial mock, you'll have to manually call Mockery with this syntax instead.

Hope this helps,


P.S. Would you like to support this newsletter and keep me writing tips for years to come? Leave a tip for any amount and make my day!

Toss a coin in the jar if you found this helpful.
Want a tip like this in your inbox every weekday? Sign up below 👇🏼

Level up your Laravel skills!

Each 2-minute email has real-world advice you can use.