Allow overwriting services in test
Set up something like this by default: http://blog.lyrixx.info/2013/04/12/symfony2-how-to-mock-services-during-functional-tests.html
Not sure how to best do this to not require a custom Kernel. Possibly make the Kernel class on the fly, extending the current Kernel or something?
looks like you can do something like this: https://github.com/FriendsOfSymfony/FOSHttpCacheBundle/blob/master/Tests/Functional/EventListener/InvalidationSubscriberTest.php
maybe simply a documentation issue?
Today I have had the same doubt and I can not do like dbu says because I have to get more service. I have done something like
$mock = $this->prophesize(ClassInterface::class);
$mock->method(Argument::any())->willReturn($return)->shouldBeCalled();
static::$kernel->getContainer()->set('id_service', $mock->reveal());
I don't know if the right way, but I was wondering add some method to Liip\FunctionaTestBundle\WebTestCase. Could it be a good idea? or is there other way to do it?
@almacbe I'm not sure to understand your problem but did you try to use getServiceMockBuilder()?
yes... but this method just create a mock of a service. I want to create a mock and add it to container because when some class call to this service, it gets the mock service, do I explain more or less @alexislefebvre ?
@almacbe Thanks, that's what I was thinking but I wasn't sure. So you want to replace an existing service and not only mock it.
yes
Any update on this?
Is there any documentaion about this feature, or some example?
symfony 3.2 deprecates setting any services into the container after the container has been built. this also affects what we can do here. there is an issue on the symfony documentation https://github.com/symfony/symfony-docs/issues/8203 - would be great if somebody digs into this topic. once a good solution is visible, it could make sense to add it to this bundle, if it can avoid boilerplate code and provide a best practice.
I was digging in this topic for a couple of days and I have created this repo with some examples of different ways to overrider services in the container.
The set method is going to be deprecated in version 4.0 but for now we can still use it. Otherwise there is only one way to overwrite a service of the DIC for a mock and it is defining this mock service in the container. You can see the repo where I have done.
Although, there is other way but it is similar than the way I propose and it is using TestDoubleBundle. Its idea is add an annotation to a service and added a mock of the service to the container instead of real object. It is a really good idea if you want to mock this service for all tests but if you want to mock the service for couple of test it is not a good solution.
So far it is my conclusion, if you have some comments please let me know.
thanks for these inputs. maybe we should just link these two things (TestDoubleBundle and your examples) in our documentation but consider it out of scope for the LiipFunctionalTestBundle?
I am not sure how add this topic to the doc because this bundle don't do nothing related to this topic. Some idea?
Maybe... but I am not sure how to do it we can add a base AppKernel as my example. This class will help you to use a different service configuration for your test.
What do you think?
maybe have a section in the readme or the doc intro that tells what is out of scope for this bundle, with pointers to other resources?
See https://github.com/symfony/symfony/pull/24418
Ok, according to the issue @nicolas-grekas linked to, it is enough to just do:
$mock = $this->createMockInAnyWayYouWant();
static::$kernel->getContainer()->set('id_service', $mock);
This should also work in future Symfony versions.
But what if you want to mock a service in the client?
The problem here is that the Client reboots the kernel a lot.
A good tip then is to use the disableBoot method to ensure that the service stays mocked:
$client = $this->createClient();
$client->disableBoot();
$client->getContainer()->set('service', $mock);
$client->request(...);
$client->request(...);
Disabling boot could not be feasible sometimes... As an example, Doctrine blows up if you're submitting a form with an EntityType field and you don't reboot the kernel.
In those case, I prefer to override the service that I need to mock in the test environment, and add an hook to inject the mock.
@Jean85 good to know!
@tarjei @Jean85 thanks so much for the advice. Good to know!