-
-
Save lyrixx/0adb8fd414451596557871d2d9af5695 to your computer and use it in GitHub Desktop.
| <?php | |
| namespace Tests\Integration; | |
| use Symfony\Bundle\FrameworkBundle\Test\KernelTestCase; | |
| use Symfony\Component\Config\FileLocator; | |
| use Symfony\Component\DependencyInjection\ContainerBuilder; | |
| use Symfony\Component\DependencyInjection\Definition; | |
| use Symfony\Component\DependencyInjection\Loader\XmlFileLoader; | |
| class ContainerTest extends KernelTestCase | |
| { | |
| private const FILTER_LIST = [ | |
| // some services can exist only in dev or prod (thus not in test env) | |
| // or some services are behind some features flags | |
| // or some services are static (thus they are not real service) | |
| ]; | |
| public function testContainer() | |
| { | |
| static::bootKernel(['debug' => true]); | |
| $projectDir = static::getContainer()->getParameter('kernel.project_dir'); | |
| $container = static::getContainer(); | |
| $builder = new ContainerBuilder(); | |
| $loader = new XmlFileLoader($builder, new FileLocator()); | |
| $loader->load($container->getParameter('debug.container.dump')); | |
| $count = 0; | |
| foreach ($builder->getDefinitions() as $id => $service) { | |
| if ($this->isSkipped($id, $service, $builder, $projectDir)) { | |
| continue; | |
| } | |
| $container->get($id); | |
| ++$count; | |
| } | |
| $this->addToAssertionCount($count); | |
| } | |
| private function isSkipped(string $id, Definition $service, ContainerBuilder $builder, string $projectDir): bool | |
| { | |
| if (str_starts_with($id, '.instanceof.') || str_starts_with($id, '.abstract.') || str_starts_with($id, '.errored.')) { | |
| return true; // Symfony internal stuff | |
| } | |
| if ($service->isAbstract()) { | |
| return true; // Symfony internal stuff | |
| } | |
| $class = $service->getClass(); | |
| if (!$class) { | |
| return true; // kernel, or alias, or abstract | |
| } | |
| if (\in_array($class, self::FILTER_LIST)) { | |
| return true; | |
| } | |
| $rc = $builder->getReflectionClass($class, false); | |
| if (!$rc) { | |
| return true; | |
| } | |
| $filename = $rc->getFileName(); | |
| if (!str_starts_with($filename, "{$projectDir}/src")) { | |
| return true; // service class not in tests/Integration | |
| } | |
| if ($rc->isAbstract()) { | |
| return true; | |
| } | |
| return false; | |
| } | |
| } |
hey @lyrixx
thanks for this snippet.
I'm trying to implement this in one huge project, and I'm facing some memory limit problems. I tried to run with 'debug' => false, or to shutdown kernel, but still have a huge memory usage with this test. Do you have some hints about this? thanks!
On project I'm working ATM:
- 6557 services in total
-
so 1008 services testedOK (1 test, 1008 assertions) Time: 00:01.455, Memory: 119.00 MB
So it looks like it does not consume too much memory
Maybe you have a memory leak somewhere...
we have more than 20.000 services and 4000 services tested, memory consumption ends at ~600 Mo just for this test 😞
Now that XmlFileLoader is deprecated, what's the best way to resolve this deprecation here? :)
Hello, I haven't tried it yet. However, I think you could take inspiration from this: https://github.com/symfony/symfony/blob/8.1/src/Symfony/Bundle/FrameworkBundle/Command/BuildDebugContainerTrait.php#L33
Thanks, that works well
FYI, I ended up with something like this as a PoC:
The differences from gist's version:
vendor/symfony, instead of narrowing tosrconly (our app has several dirs with production code, I did not want to list them all or to prepare complex logic)falseAnyway, thanks for sharing, it was good to make some kind of experiment. What I found more than
lint:containeris that we rely onEventDispatcher, not onEventDispatcherInterface, so when traceable event dispatcher is injected intestenvironment, there'sTypeError, which means we should fix the signatures and use the interface as a contract.PS. in our case
bootstrapContainer()has logic, I just removed it as it's crafted for our code. But if there are any things that need to be pre-defined before services are created (like$_SERVER['HTTP_CLIENT_IP']for example), you also need to do it before iterating over container.