{"id":15008348,"url":"https://github.com/symfonytest/symfonydependencyinjectiontest","last_synced_at":"2025-05-14T14:10:07.147Z","repository":{"id":10424095,"uuid":"12585067","full_name":"SymfonyTest/SymfonyDependencyInjectionTest","owner":"SymfonyTest","description":"Library for testing user classes related to the Symfony Dependency Injection Component","archived":false,"fork":false,"pushed_at":"2025-03-09T19:13:08.000Z","size":255,"stargazers_count":240,"open_issues_count":9,"forks_count":48,"subscribers_count":13,"default_branch":"master","last_synced_at":"2025-04-15T05:16:02.902Z","etag":null,"topics":["symfony"],"latest_commit_sha":null,"homepage":"","language":"PHP","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SymfonyTest.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2013-09-04T07:51:48.000Z","updated_at":"2025-03-08T18:08:53.000Z","dependencies_parsed_at":"2024-01-23T14:56:29.804Z","dependency_job_id":"edfdec0d-0e19-44f2-9c9b-0fba0e945c48","html_url":"https://github.com/SymfonyTest/SymfonyDependencyInjectionTest","commit_stats":{"total_commits":118,"total_committers":33,"mean_commits":"3.5757575757575757","dds":0.728813559322034,"last_synced_commit":"9e0106e2a04c18428a4b9063bd1ebdc3036897a5"},"previous_names":[],"tags_count":37,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymfonyTest%2FSymfonyDependencyInjectionTest","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymfonyTest%2FSymfonyDependencyInjectionTest/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymfonyTest%2FSymfonyDependencyInjectionTest/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SymfonyTest%2FSymfonyDependencyInjectionTest/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SymfonyTest","download_url":"https://codeload.github.com/SymfonyTest/SymfonyDependencyInjectionTest/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254160559,"owners_count":22024571,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["symfony"],"created_at":"2024-09-24T19:17:44.736Z","updated_at":"2025-05-14T14:10:02.132Z","avatar_url":"https://github.com/SymfonyTest.png","language":"PHP","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SymfonyDependencyInjectionTest\n\n*By Matthias Noback and contributors*\n\n[![Build Status](https://github.com/SymfonyTest/SymfonyDependencyInjectionTest/actions/workflows/ci.yaml/badge.svg)](https://github.com/SymfonyTest/SymfonyDependencyInjectionTest/actions/workflows/ci.yaml)\n\nThis library contains several PHPUnit test case classes and many semantic [assertions](#list-of-assertions) which\nyou can use to functionally test your [container extensions](#testing-a-container-extension) (or \"bundle extensions\")\nand [compiler passes](#testing-a-compiler-pass). It also provides the tools to functionally test your container\nextension (or \"bundle\") configuration by verifying processed values from different types of configuration files.\n\nBesides verifying their correctness, this library will also help you to adopt a TDD approach when developing\nthese classes.\n\n## Installation\n\nUsing Composer:\n\n```bash\ncomposer require --dev matthiasnoback/symfony-dependency-injection-test\n```\n\n## Usage\n\n### Testing a container extension\n\nTo test your own container extension class ``MyExtension`` create a class and extend from\n``Matthias\\SymfonyDependencyInjectionTest\\PhpUnit\\AbstractExtensionTestCase``. Then implement the\n``getContainerExtensions()`` method:\n\n```php\n\u003c?php\n\nuse Matthias\\SymfonyDependencyInjectionTest\\PhpUnit\\AbstractExtensionTestCase;\n\nclass MyExtensionTest extends AbstractExtensionTestCase\n{\n    protected function getContainerExtensions(): array\n    {\n        return [\n            new MyExtension()\n        ];\n    }\n}\n```\n\nBasically you will be testing your extension's load method, which will look something like this:\n\n```php\n\u003c?php\n\nclass MyExtension extends Extension\n{\n    public function load(array $config, ContainerBuilder $container)\n    {\n        $loader = new XmlFileLoader($container, new FileLocator(__DIR__));\n        $loader-\u003eload('services.xml');\n\n        // maybe process the configuration values in $config, then:\n\n        $container-\u003esetParameter('parameter_name', 'some value');\n    }\n}\n```\n\nSo in the test case you should test that after loading the container, the parameter has been set correctly:\n\n```php\n\u003c?php\n\nclass MyExtensionTest extends AbstractExtensionTestCase\n{\n    /**\n     * @test\n     */\n    public function after_loading_the_correct_parameter_has_been_set()\n    {\n        $this-\u003eload();\n\n        $this-\u003eassertContainerBuilderHasParameter('parameter_name', 'some value');\n    }\n}\n```\n\nTo test the effect of different configuration values, use the first argument of ``load()``:\n\n```php\n\u003c?php\n\nclass MyExtensionTest extends AbstractExtensionTestCase\n{\n    /**\n     * @test\n     */\n    public function after_loading_the_correct_parameter_has_been_set()\n    {\n        $this-\u003eload(['my' =\u003e ['enabled' =\u003e 'false']);\n\n        ...\n    }\n}\n```\n\nTo prevent duplication of required configuration values, you can provide some minimal configuration, by overriding\nthe ``getMinimalConfiguration()`` method of the test case.\n\n### Testing a compiler pass\n\nTo test a compiler pass, create a test class and extend from\n``Matthias\\SymfonyDependencyInjectionTest\\PhpUnit\\AbstractCompilerPassTestCase``. Then implement the ``registerCompilerPass()`` method:\n\n```php\n\u003c?php\n\nuse Matthias\\SymfonyDependencyInjectionTest\\PhpUnit\\AbstractCompilerPassTestCase;\n\nclass MyCompilerPassTest extends AbstractCompilerPassTestCase\n{\n    protected function registerCompilerPass(ContainerBuilder $container): void\n    {\n        $container-\u003eaddCompilerPass(new MyCompilerPass());\n    }\n}\n```\n\nIn each test you can first set up the ``ContainerBuilder`` instance properly, depending on what your compiler pass is\nexpected to do. For instance you can add some definitions with specific tags you will collect. Then after the \"arrange\"\nphase of your test, you need to \"act\", by calling the ``compile()``method. Finally you may enter the \"assert\" stage and\nyou should verify the correct behavior of the compiler pass by making assertions about the ``ContainerBuilder``\ninstance.\n\n```php\n\u003c?php\n\nclass MyCompilerPassTest extends AbstractCompilerPassTestCase\n{\n    /**\n     * @test\n     */\n    public function if_compiler_pass_collects_services_by_adding_method_calls_these_will_exist()\n    {\n        $collectingService = new Definition();\n        $this-\u003esetDefinition('collecting_service_id', $collectingService);\n\n        $collectedService = new Definition();\n        $collectedService-\u003eaddTag('collect_with_method_calls');\n        $this-\u003esetDefinition('collected_service', $collectedService);\n\n        $this-\u003ecompile();\n\n        $this-\u003eassertContainerBuilderHasServiceDefinitionWithMethodCall(\n            'collecting_service_id',\n            'add',\n            [\n                new Reference('collected_service')\n            ]\n        );\n    }\n}\n```\n\n#### Standard test for unobtrusiveness\n\nThe ``AbstractCompilerPassTestCase`` class always executes one specific test -\n``compilation_should_not_fail_with_empty_container()`` - which makes sure that the compiler pass is unobtrusive. For\nexample, when your compiler pass assumes the existence of a service, an exception will be thrown, and this test will\nfail:\n\n```php\n\u003c?php\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\n\nclass MyCompilerPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container)\n    {\n        $definition = $container-\u003egetDefinition('some_service_id');\n\n        ...\n    }\n}\n```\n\nSo you need to always add one or more guard clauses inside the ``process()`` method:\n\n```php\n\u003c?php\n\nuse Symfony\\Component\\DependencyInjection\\Compiler\\CompilerPassInterface;\nuse Symfony\\Component\\DependencyInjection\\ContainerBuilder;\n\nclass MyCompilerPass implements CompilerPassInterface\n{\n    public function process(ContainerBuilder $container)\n    {\n        if (!$container-\u003ehasDefinition('some_service_id')) {\n            return;\n        }\n\n        $definition = $container-\u003egetDefinition('some_service_id');\n\n        ...\n    }\n}\n```\n\n\u003e #### Use ``findDefinition()`` instead of ``getDefinition()``\n\u003e\n\u003e You may not know in advance if a service id stands for a service definition, or for an alias. So instead of\n\u003e ``hasDefinition()`` and ``getDefinition()`` you may consider using ``has()`` and ``findDefinition()``. These methods\n\u003e recognize both aliases and definitions.\n\n### Test different configuration file formats\n\nThe Symfony DependencyInjection component supports many different types of configuration loaders: Yaml, XML, and\nPHP files, but also closures. When you create a ``Configuration`` class for your bundle, you need to make sure that each\nof these formats is supported. Special attention needs to be given to XML files.\n\nIn order to verify that any type of configuration file will be correctly loaded by your bundle, you must install the\n[SymfonyConfigTest](https://github.com/SymfonyTest/SymfonyConfigTest) library and create a test class that extends\nfrom ``AbstractExtensionConfigurationTestCase``:\n\n```php\n\u003c?php\n\nuse Matthias\\SymfonyDependencyInjectionTest\\PhpUnit\\AbstractExtensionConfigurationTestCase;\n\nclass ConfigurationTest extends AbstractExtensionConfigurationTestCase\n{\n    protected function getContainerExtension()\n    {\n        return new TwigExtension();\n    }\n\n    protected function getConfiguration()\n    {\n        return new Configuration();\n    }\n}\n```\n\nNow inside each test method you can use the ``assertProcessedConfigurationEquals($expectedConfiguration, $sources)``\nmethod to verify that after loading the given sources the processed configuration equals the expected array of values:\n\n```yaml\n# in Fixtures/config.yml\ntwig:\n    extensions: ['twig.extension.foo']\n```\n\n```xml\n\u003c!-- in Fixtures/config.xml --\u003e\n\u003ccontainer\u003e\n    \u003ctwig:config\u003e\n        \u003ctwig:extension\u003etwig.extension.bar\u003c/twig:extension\u003e\n    \u003c/twig:config\u003e\n\u003c/container\u003e\n```\n\n```php\n\u003c?php\n...\n\nclass ConfigurationTest extends AbstractExtensionConfigurationTestCase\n{\n    ...\n\n    /**\n     * @test\n     */\n    public function it_converts_extension_elements_to_extensions()\n    {\n        $expectedConfiguration = [\n            'extensions' =\u003e ['twig.extension.foo', 'twig.extension.bar']\n        ];\n\n        $sources = [\n            __DIR__ . '/Fixtures/config.yml',\n            __DIR__ . '/Fixtures/config.xml',\n        ];\n\n        $this-\u003eassertProcessedConfigurationEquals($expectedConfiguration, $sources);\n    }\n}\n```\n\n## List of assertions\n\nThese are the available semantic assertions for each of the test cases shown above:\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasService($serviceId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasService($serviceId, $expectedClass)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id and class.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderNotHasService($serviceId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test does not have a service definition with the given id.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasSyntheticService($serviceId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a synthetic service with the given id.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasAlias($aliasId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has an alias.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasAlias($aliasId, $expectedServiceId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has an alias and that it is an alias for the given service id.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasParameter($parameterName)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a parameter.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasParameter($parameterName, $expectedParameterValue)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a parameter and that its value is the given value.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasExactParameter($parameterName)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a parameter.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasExactParameter($parameterName, $expectedParameterValue)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a parameter and that its value is the given value, as well as its type matches given value type.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithArgument($serviceId, $argumentIndex)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id, which has an argument at\nthe given index.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithArgument($serviceId, $argumentIndex, $expectedValue)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id, which has an argument at\nthe given index, and its value is the given value.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithServiceLocatorArgument($serviceId, $argumentIndex, $expectedValue)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id, which has an argument\nat the given index, and its value is a ServiceLocator with a reference-map equal to the given value.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithMethodCall($serviceId, $method, array $arguments = [], $index = null)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id, which has a method call to\nthe given method with the given arguments. If index is provided, invocation index order of method call is asserted as well.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithTag($serviceId, $tag, array $attributes = [])\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id, which has the given tag with the given arguments.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceDefinitionWithParent($serviceId, $parentServiceId)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a service definition with the given id which is a decorated service and it has the given parent service.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eassertContainerBuilderHasServiceLocator($serviceId, $expectedServiceMap)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eAssert that the \u003ccode\u003eContainerBuilder\u003c/code\u003e for this test has a ServiceLocator service definition with the given id.\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Available methods to set up container\n\nIn all test cases shown above, you have access to some methods to set up the\ncontainer:\n\n\u003cdl\u003e\n\u003cdt\u003e\u003ccode\u003esetDefinition($serviceId, $definition)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eSet a definition. The second parameter is a \u003ccode\u003eDefinition\u003c/code\u003e class\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003eregisterService($serviceId, $class)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eA shortcut for \u003ccode\u003esetDefinition\u003c/code\u003e. It returns a \u003ccode\u003eDefinition\u003c/code\u003e object that can be modified if necessary.\u003c/dd\u003e\n\u003cdt\u003e\u003ccode\u003esetParameter($parameterId, $parameterValue)\u003c/code\u003e\u003c/dt\u003e\n\u003cdd\u003eSet a parameter.\u003c/dd\u003e\n\u003c/dl\u003e\n\n## Version Guidance\n\n| Version | Released     | PHPUnit             | Status     |\n|---------|--------------|---------------------|------------|\n| 6.x     | Aug 8, 2024  | 10.5, 11.x and 12.x | Latest     |\n| 5.x     | Nov 22, 2023 | 9.6 and 10.x        | Bugfixes   |\n| 4.x     | Mar 28, 2019 | 8.x and 9.x         | Bugfixes   |\n| 3.x     | Mar 5, 2018  | 7.x                 | Bugfixes   |\n| 2.x     | May 9, 2017  | 6.x                 | Bugfixes   |\n| 1.x     | Jul 4, 2016  | 4.x and 5.x         | EOL        |\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymfonytest%2Fsymfonydependencyinjectiontest","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsymfonytest%2Fsymfonydependencyinjectiontest","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsymfonytest%2Fsymfonydependencyinjectiontest/lists"}