LiipFunctionalTestBundle icon indicating copy to clipboard operation
LiipFunctionalTestBundle copied to clipboard

Allow overwriting services in test

Open colinfrei opened this issue 12 years ago • 18 comments

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?

colinfrei avatar Nov 11 '13 16:11 colinfrei

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?

dbu avatar Aug 04 '14 22:08 dbu

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 avatar May 02 '16 13:05 almacbe

@almacbe I'm not sure to understand your problem but did you try to use getServiceMockBuilder()?

alexislefebvre avatar May 02 '16 16:05 alexislefebvre

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 avatar May 03 '16 16:05 almacbe

@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.

alexislefebvre avatar May 03 '16 17:05 alexislefebvre

yes

almacbe avatar May 03 '16 17:05 almacbe

Any update on this?

jakesylvestre avatar Mar 23 '17 20:03 jakesylvestre

Is there any documentaion about this feature, or some example?

fearintino avatar Jul 31 '17 12:07 fearintino

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.

dbu avatar Jul 31 '17 13:07 dbu

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.

almacbe avatar Sep 18 '17 12:09 almacbe

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?

dbu avatar Sep 19 '17 15:09 dbu

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?

almacbe avatar Sep 20 '17 13:09 almacbe

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?

dbu avatar Sep 21 '17 11:09 dbu

See https://github.com/symfony/symfony/pull/24418

nicolas-grekas avatar Oct 04 '17 07:10 nicolas-grekas

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(...);

tarjei avatar Jan 17 '18 10:01 tarjei

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 avatar Jan 17 '18 11:01 Jean85

@Jean85 good to know!

tarjei avatar Jan 17 '18 11:01 tarjei

@tarjei @Jean85 thanks so much for the advice. Good to know!

almacbe avatar Jan 17 '18 13:01 almacbe