matthiasnoback/symfony-dependency-injection-test
Installation
composer require --dev matthiasnoback/symfony-dependency-injection-test
First Test Case
Extend AbstractExtensionTestCase for container extensions or AbstractCompilerPassTestCase for compiler passes.
Example:
use Matthias\SymfonyDependencyInjectionTest\PhpUnit\AbstractExtensionTestCase;
class MyExtensionTest extends AbstractExtensionTestCase
{
protected function getContainerExtensions(): array
{
return [new MyExtension()];
}
}
Run Tests
phpunit
Test a simple container extension that loads services from configuration:
public function testLoadsServicesFromConfig()
{
$this->loadFromConfiguration(
['service' => ['enabled' => true]]
);
$this->assertContainerBuilderHasService('my_service');
}
Configuration Loading
Use loadFromConfiguration() to simulate loading YAML/XML/PHP config:
$this->loadFromConfiguration(['param' => 'value']);
Service Verification Assert services exist, are public, or have specific tags:
$this->assertContainerBuilderHasService('service_name');
$this->assertContainerBuilderHasPublicService('service_name');
$this->assertContainerBuilderHasTaggedService('service_name', 'tag_name');
Parameter Validation Check if parameters are defined and match expected values:
$this->assertContainerBuilderHasParameter('param_name');
$this->assertContainerBuilderHasParameter('param_name', 'expected_value');
Extension Setup
Extend AbstractCompilerPassTestCase and define passes:
protected function getCompilerPasses(): array
{
return [new MyCompilerPass()];
}
Pass Execution
Simulate pass execution with compile():
$this->compile();
Post-Compilation Checks Verify services/parameters after compilation:
$this->assertContainerBuilderHasService('modified_service');
Laravel-Specific Setup
Use Laravel’s Container facade to instantiate extensions/passes:
$extension = app()->make(MyExtension::class);
$this->loadFromConfiguration([...]);
Testing Service Providers
Mock Laravel’s ServiceProvider boot/register methods:
$this->assertContainerBuilderHasService('app\MyService');
Configuration Overrides Override Laravel’s config in tests:
config(['my_package.enabled' => true]);
$this->loadFromConfiguration(config('my_package'));
Configuration Merging
loadFromConfiguration() merges with existing config. Clear the container first if needed:
$this->resetContainer();
$this->loadFromConfiguration([...]);
loadFromExtension() for extension-specific config isolation.Service Name Conflicts
App\Services\MyService) may conflict with test assertions.$this->assertContainerBuilderHasService('app.services.my_service');
Compiler Pass Order
getCompilerPasses().setPriority() in passes for explicit ordering.Laravel-Specific Quirks
ServiceProvider lifecycle (boot/register) isn’t directly testable.Dump Container State
Use dumpContainerState() to inspect services/parameters:
$this->dumpContainerState();
Assertion Failures
assertContainerBuilderHasServiceDefinitionThat() for granular checks:
$this->assertContainerBuilderHasServiceDefinitionThat(
'service_name',
$this->isInstanceOf(MyService::class)
);
Configuration Validation
assertConfigurationIsValid():
$this->assertConfigurationIsValid([...]);
Custom Assertions
Extend AbstractExtensionTestCase to add custom assertions:
protected function assertCustomCondition()
{
$this->assertTrue($this->container->has('expected_service'));
}
Mocking Dependencies Use PHPUnit’s mocking to isolate tests:
$this->mockService('dependency', Mockery::mock(MyDependency::class));
Laravel-Specific Extensions Create a base test case for Laravel projects:
abstract class LaravelExtensionTestCase extends AbstractExtensionTestCase
{
protected function getContainer()
{
return app()->make('service_container');
}
}
Reset Container Between Tests Avoid state leakage:
protected function tearDown(): void
{
$this->resetContainer();
parent::tearDown();
}
Focus on Critical Paths Prioritize testing:
How can I help you explore Laravel packages today?