Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[DI] Cannot replace autowired services for testing purpose #35176

Closed
lucascourot opened this issue Jan 2, 2020 · 5 comments
Closed

[DI] Cannot replace autowired services for testing purpose #35176

lucascourot opened this issue Jan 2, 2020 · 5 comments

Comments

@lucascourot
Copy link

Symfony version(s) affected: 3.3+

Description
Services used as autowired arguments are not replaced by $container->set() even though they are replaced in the container itself. Thus I found quite a weird behaviour when trying to stub a service for testing purpose.

How to reproduce
Please see the repo I created to reproduce the bug, services are public in test env

Launch phpunit

See the different behaviour in the controller executed by phpunit in the controller test

Additional context
Related feature : #24418

@lucascourot
Copy link
Author

lucascourot commented Jan 3, 2020

I found how to fix my problem

services:
    _defaults:
        autowire: true
        autoconfigure: true

    App\Coffee\WaterTankInterface:
        alias: App\Coffee\Infra\FullTank
        public: true

This works fine, I can use $container->set() to stub my interface during tests to replace the default alias.

// Test extends Symfony\Bundle\FrameworkBundle\Test\KernelTestCase
    public function testShouldReturn400WhenWaterTankIsEmpty()
    {
        // Given
        $kernel = self::bootKernel();

        $kernel->getContainer()->set(WaterTankInterface::class, new EmptyTank());

        // When
        $response = $kernel->handle(Request::create('/coffee', 'POST'));

        // Then
        $this->assertSame(400, $response->getStatusCode());
    }

However, this code below doesn't produce the same result. I thought it behaves as the code above but it looks like it isn't:

services:
    _defaults:
        autowire: true
        autoconfigure: true
        public: true

    App\Coffee\WaterTankInterface:
        alias: App\Coffee\Infra\FullTank

Could someone explain me why and if it's a bug or not please ?

To easily reproduce the bug please checkout this PR branch lucascourot/sf-issue-replacing-services#2 and read its description

@carsonbot
Copy link

Hey, thanks for your report!
There has not been a lot of activity here for a while. Is this bug still relevant? Have you managed to find a workaround?

@stof
Copy link
Member

stof commented Jan 4, 2021

App\Coffee\WaterTankInterface is not a service definition in your case, but an alias of the App\Coffee\Infra\FullTank. During the container compilation, references to aliases are resolved to the actual reference (to avoid having to resolve the alias at runtime, which would add some overhead).
So you should be setting the App\Coffee\Infra\FullTank service instead.

@carsonbot carsonbot removed the Stalled label Jan 4, 2021
@stof
Copy link
Member

stof commented Jan 4, 2021

note that when your alias is public and the targeted service is private, the container will actually inline the service into its alias (and update references accordingly) as it cannot remove the public name while it can remove a private name. That's why your workaround works.

@B-Galati
Copy link
Contributor

Looks related to #48938

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

6 participants