Suppose the following scenario:
- I have a class that makes calls to an external service
- The class implements an interface and is defined as preferred implementation for this interface in
di.xml
- A block receives this interface as constructor parameter
- I want to test a Magento request in an integration test that uses this block
I don't want to actually call the external service, so I would like to mock that class and wonder what's the best way to do so.
I know that you can define DI preferences on the fly with
$objectManager->configure(
['preferences' => [TheInterface::class => MockClass::class]]
);
but this requires defining a mock class MockClass
yourself, I cannot use a PHPUnit mock object.
This works okay if the injected class is a factory because I can create a mock factory that creates the actual mock object.
But is this the only way or am I missing something?
Update:
The suggested method
$objectManager->addSharedInstance($mock, TheInterface::class);
looked good first, but only worked as long as there were no preferences defined. These take precedene over shared instances.
I tried to dynamically remove the preference:
$this->objectManager->configure(
['preferences' => [TheInterface::class => null]]
);
But unfortunately Magento calls ltrim($to, '\\')
on the argument, which converts it to an empty string. This results in:
ReflectionException: Class does not exist