Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Symfony 4.2 How to do a service public only for tests

I have the solution to make the service public. In the services.yml

    test_phpdocxService:
          alias: App\Service\PhpDocxService
          public: true

I try to access the service:

$container = self::$container;
$phpDocxService = $container->get('test_phpdocxService');

$this->filename = $phpDocxService->generateDocxDocument('docx/aaa.html.twig', $data);

But I find it not so nice. Is there an another way to do that?

like image 285
olek07 Avatar asked Jan 31 '19 17:01

olek07


3 Answers

Okay. So there is an issue about testing private services that are not used anywhere in your app. It is still open and being discussed but basically, for now, you need to typehint against your private service somewhere in your app before you can access it in a test.

Using a fresh 4.4.2 install:

# src/Service/PhpDocxService.php
namespace App\Service;
class PhpDocxService
{
    public function sayHello()
    {
        return 'hello';
    }
}

# src/Controller/MyController.php
namespace App\Controller;

use App\Service\PhpDocxService;


class MyController
{
    #****** This is the secret ******
    public function __construct(PhpDocxService $phpDocxService)
    {

    }
}

# src/tests/MyTest.php
namespace App\Tests;

use App\Service\PhpDocxService;
use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class MyTest extends WebTestCase
{
    public function testServiceFound()
    {
        self::bootKernel();

        // gets the special container that allows fetching private services
        $container = self::$container;

        $phpDocxService = $container->get(PhpDocxService::class);

        $this->assertEquals('hello',$phpDocxService->sayHello());
    }
}

Typehint your service in a controller's constructor and everything works as expected.

like image 113
Cerad Avatar answered Nov 17 '22 03:11

Cerad


You need to create in config/config_test.yml and declare that service is public and other configuration for tests there .

This approach you can use in symfony 3/4.

You can read tutorial here: https://symfonycasts.com/screencast/phpunit/integration-tests

About Symfony simple testing 4.1 feature please read @Cerad post

like image 21
nicandr Avatar answered Nov 17 '22 01:11

nicandr


YOU DON'T! :)

Instead, you use the new Simpler service testing, implemented in Symfony 4.1.

With that, tests based on WebTestCase and KernelTestCase now access to a special container via the static::$container property that allows fetching non-removed private services.

And that means that private services are automatically public in tests if you use that container.

Just do something like:

use Symfony\Bundle\FrameworkBundle\Test\WebTestCase;

class SomeClassToTest extends WebTestCase
{
    public function getService(string $service)
    {
        self::bootKernel();
        $container = self::$kernel->getContainer();
        $container = self::$container;

        return self::$container->get($service);
    }

    public function tesSomething()
    {
        $imageProcessor = $this->getService('app.some.service');
    }

And now you can get the private 'app.some.service' service in testing environments.

like image 3
Eduardo Fernandes Avatar answered Nov 17 '22 02:11

Eduardo Fernandes