imJohnBon's avatar

Testing and the "new" keyword

Quick question, I know when it comes to Unit tests, it's best to avoid creating new objects with the "new" keyword and use dependency injection instead. That all makes sense to me, since it allows you to mock the objects.

However, something I often see in Laravel's docs is stuff like this (actually something Taylor just tweeted):

https://pbs.twimg.com/media/Cpg68j5UsAACdlG.jpg:large

It seems like in these cases, there's no way around new'ing up an instance of an object. But would using code like that effect testability?

0 likes
3 replies
jimmck's avatar

I think you are referring to 'mocking' an Object. Injection just hides the source of the new reference. Object creation needs to be tested. Sometimes however you don't want to send a real email or queue a real test. Than a 'mocked' object can allow your test to flow. Just don't benchmark 'mocked' execution times.

bugsysha's avatar

If it's something like a model and I need the id of that model then I mock it, if not I just new it up. Everything depends on what are you trying to do.

ifpingram's avatar

@imJohnBon to allow mocking of the objects in question, I would make the object before putting it into the argument. The docs are not focussed on testability, so this is understandable it is written like they are. To allow mocking of the objects, pull the object from the container prior to using it as an argument, e.g.

$shipping_status_updated = app(ShippingStatusUpdated::class, ['update' => $update]);
broadcast($shipping_status_updated);

Then in your tests, you can swap out ShippingStatusUpdated::class in the usual way:

$shipping_status_updated_mock = Mockery::mock(ShippingStatusUpdated::class);
$this->app->instance(ShippingStatusUpdated::class, $shipping_status_updated_mock);

Please or to participate in this conversation.