Reputation: 125
Today, I've tried to upgrade my project to the new version of Symfony (3.3), and I'm encountering a problem with my mocks.
Until today, I was doing my mocks like this:
$client = $this->makeClient();
$mockObject = new \stdClass();
$mock = $this->getMockBuilder('SomeClass')
->disableOriginalConstructor()
->setMethods(['method1', 'method2'])
->getMock();
$mock->expects($this->once())
->method('method1')
->will($this->returnValue($mockObject));
$client->getContainer()->set('my_service', $mock);
Here, method1
is just a Guzzle post, nothing else.
Now, I'm getting the following error:
Setting the "my_service" pre-defined service is deprecated since Symfony 3.3 and won't be supported anymore in Symfony 4.0: 1x
After some research, it seems that I cannot use the last line of my code. Problem is, I can't see nor find any solution to solve this deprecation.
Upvotes: 1
Views: 2376
Reputation: 36241
There's few ways of solving your problem.
TestDoubleBundle
TestDoubleBundle makes it easier to create test doubles. You can use dependency injection tags to automatically replace a service with either a stub or a fake.
Override the container
Another way is to extend the container in the test environment, so it allows stubbing. Here's a draft of the idea:
<?php
namespace Zalas\Test\DependencyInjection;
use Symfony\Component\DependencyInjection\Container;
class MockerContainer extends Container
{
/**
* @var object[] $stubs
*/
private $stubs = array();
public function stub($serviceId, $stub)
{
if (!$this->has($serviceId)) {
throw new \InvalidArgumentException(sprintf('Cannot stub a non-existent service: "%s"', $serviceId));
}
$this->stubs[$serviceId] = $stub;
}
/**
* @param string $id
* @param integer $invalidBehavior
*
* @return object
*/
public function get($id, $invalidBehavior = self::EXCEPTION_ON_INVALID_REFERENCE)
{
if (array_key_exists($id, $this->stubs)) {
return $this->stubs[$id];
}
return parent::get($id, $invalidBehavior);
}
/**
* @param string $id
*
* @return boolean
*/
public function has($id)
{
if (array_key_exists($id, $this->stubs)) {
return true;
}
return parent::has($id);
}
}
To enable this container you'll need to override the getContainerBaseClass
method in your AppKernel
:
/**
* @return string
*/
protected function getContainerBaseClass()
{
if ('test' == $this->environment) {
return '\Zalas\Test\DependencyInjection\MockerContainer';
}
return parent::getContainerBaseClass();
}
You might need to tweak the code a bit, perhaps declare MockerContainer::$stubs
as static (although if your previous approach worked it shouldn't be needed - it might be needed if you need to stub for multiple requests).
Now you should be able to use the container to stub services like this:
$client->getContainer()->stub('my_service', $myServiceStub);
Use a synthetic service
Another way of working around your issue is defining your service as synthetic. You could write a compiler pass that would only mark the service as synthetic in a test environment.
Upvotes: 2
Reputation: 39450
Your question is also discussed here.
You can take a look at this osservation:
Note that you don't need to fix the deprecations when moving to 3.3. But you will when moving to 4.0.
And this workaround:
Well, you can mark these tests as
@legacy
to avoid making them fail temporarily, to give you time to migrate the tests, if that takes time. This is the whole point of deprecations: you can migrate progressively (I also prefer removing deprecations as fast as possible, but for some of them, it may require more time)
Upvotes: 1