Weave Code
Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Symfony Phpunit Laravel Package

drjele/symfony-phpunit

Symfony bridge for running PHPUnit tests with a simple, consistent setup. Provides helpers and configuration to integrate PHPUnit into Symfony projects, smoothing bootstrapping and test execution across environments.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation Add the package to your Laravel project via Composer:

    composer require drjele/symfony-phpunit --dev
    

    Ensure phpunit is listed in require-dev in composer.json.

  2. Basic Configuration The package extends Symfony’s PHPUnit bridge, so no Laravel-specific config is needed. Start by publishing the default PHPUnit config (if using Symfony’s bridge):

    php vendor/bin/phpunit --configuration=phpunit.xml.dist
    

    For Laravel, ensure your phpunit.xml extends Symfony’s bridge (if applicable) or use Laravel’s default config.

  3. First Use Case: Data Providers Simplify test data setup with Symfony’s DataProvider trait:

    use Symfony\Component\DependencyInjection\Tests\DataProvider\DataProviderInterface;
    
    class UserTest extends TestCase implements DataProviderInterface
    {
        public function provideTestData()
        {
            return [
                'valid user' => [['name' => 'John', 'email' => '[email protected]']],
                'invalid email' => [['name' => 'Jane', 'email' => 'invalid-email']],
            ];
        }
    
        /**
         * @dataProvider provideTestData
         */
        public function testUserCreation(array $userData)
        {
            $user = User::create($userData);
            $this->assertDatabaseHas('users', $userData);
        }
    }
    

Implementation Patterns

1. Dependency Injection in Tests

Leverage Symfony’s DI container for test dependencies:

use Symfony\Component\DependencyInjection\ContainerInterface;

class ServiceTest extends TestCase
{
    private ContainerInterface $container;

    protected function setUp(): void
    {
        $this->container = self::getContainer();
    }

    public function testServiceDependency()
    {
        $service = $this->container->get('App\\Services\\UserService');
        $this->assertInstanceOf(UserService::class, $service);
    }
}

Tip: Use Laravel’s createApplication() in TestCase to access the container.


2. Mocking with Symfony’s ExpressionLanguage

Replace manual mocks with Symfony’s ExpressionLanguage for dynamic test logic:

use Symfony\Component\ExpressionLanguage\ExpressionLanguage;

class OrderTest extends TestCase
{
    public function testOrderStatus()
    {
        $language = new ExpressionLanguage();
        $expression = $language->parse('order.status === "paid"');
        $result = $expression->evaluate([
            'order' => ['status' => 'paid', 'amount' => 100],
        ]);
        $this->assertTrue($result);
    }
}

3. Integration with Laravel’s Testing

Combine with Laravel’s RefreshDatabase or MigrateFreshDatabase traits:

use Illuminate\Foundation\Testing\RefreshDatabase;
use Symfony\Component\DependencyInjection\Tests\DataProvider\DataProviderInterface;

class MigrationTest extends TestCase implements DataProviderInterface
{
    use RefreshDatabase;

    public function provideMigrations()
    {
        return [
            'users table' => ['users'],
            'posts table' => ['posts'],
        ];
    }

    /**
     * @dataProvider provideMigrations
     */
    public function testTableExists(string $table)
    {
        $this->assertTrue(Schema::hasTable($table));
    }
}

4. Custom Assertions

Extend Symfony’s assertions for domain-specific checks:

use Symfony\Component\Validator\Tests\Constraint\Valid;

class ValidatorTest extends TestCase
{
    public function testEmailValidation()
    {
        $validator = $this->container->get('validator');
        $constraint = new Valid();
        $violations = $validator->validate('invalid-email', $constraint);
        $this->assertCount(1, $violations);
    }
}

Gotchas and Tips

Pitfalls

  1. Container Initialization

    • Issue: Symfony’s DI container may not auto-initialize in Laravel tests.
    • Fix: Explicitly boot the container in setUp():
      protected function setUp(): void
      {
          $this->app = require __DIR__.'/../../bootstrap/app.php';
          $this->app->make(Kernel::class)->boot();
      }
      
  2. DataProvider Conflicts

    • Issue: Naming collisions with Laravel’s DataProvider trait.
    • Fix: Use fully qualified namespaces:
      use Symfony\Component\DependencyInjection\Tests\DataProvider\DataProviderInterface;
      
  3. ExpressionLanguage Security

    • Issue: Dynamic expressions can expose security risks.
    • Fix: Restrict allowed functions/variables in the ExpressionLanguage constructor:
      $language = new ExpressionLanguage([
          'functions' => ['strtolower' => 'strtolower'],
          'variables' => ['order' => $orderData],
      ]);
      

Debugging Tips

  1. Enable Symfony Debug Mode Add to phpunit.xml:

    <php>
        <env name="SYMFONY_DEBUG" value="1"/>
    </php>
    
  2. Dump Container Services Inspect available services:

    $services = $this->container->getServiceIds();
    dump($services);
    
  3. Test Isolation Use KernelInterface::SHARE_EMPTY_ENVIRONMENT to avoid shared state:

    $kernel = self::bootKernel(['environment' => 'test']);
    

Extension Points

  1. Custom Data Providers Create reusable providers for complex test data:

    class UserDataProvider implements DataProviderInterface
    {
        public function provideUsers()
        {
            return [
                'admin' => [['role' => 'admin']],
                'guest' => [['role' => 'guest']],
            ];
        }
    }
    
  2. Hook into Symfony Events Extend test lifecycle with Symfony’s event system:

    use Symfony\Component\EventDispatcher\EventSubscriberInterface;
    
    class TestEventSubscriber implements EventSubscriberInterface
    {
        public static function getSubscribedEvents()
        {
            return [
                'kernel.test' => 'onTestStart',
            ];
        }
    
        public function onTestStart()
        {
            // Pre-test logic (e.g., seed DB)
        }
    }
    
  3. Laravel-Specific Extensions Override Symfony’s TestCase to integrate with Laravel’s helpers:

    abstract class LaravelSymfonyTestCase extends TestCase
    {
        use CreatesApplication;
    
        protected function getContainer()
        {
            return $this->app->get('kernel')->getContainer();
        }
    }
    
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
adachsoft/changelog-linter
adachsoft/collection
payerurl/telegrambot-crypto-payment-instant-payout
dskripchenko/laravel-hybrid-search
riorizkyrainey/lara-ced
mehedimi/static-vel
zharp/zharp
nonsapiens/bigquery-model-sync
lgu-bayambang-ict-office/lgu-laravel-development-standards
andydefer/laravel-support
se7enxweb/flysystem
lampwick/laravel
jeslage/statamic-emojis
micahdshackelford/rmap-laravel
draftsmaninc/draftsman
square-bit/laravel-volition
himito/laravel-mailman
htinlynn/genius-helper
maco-studios/hephaestus
adachsoft/php-code-style