Weave Code
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

Phpunit Test Service Container Laravel Package

matthiasnoback/phpunit-test-service-container

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require --dev matthiasnoback/phpunit-test-service-container
    
  2. Extend the base test case in your test class:
    use MatthiasNoback\PHPUnitTestServiceContainer\TestCase;
    
    class MyTest extends TestCase
    {
        // Your tests here
    }
    
  3. Create a service provider to define test dependencies:
    use MatthiasNoback\PHPUnitTestServiceContainer\ServiceProviderInterface;
    use Pimple\Container;
    use Pimple\ServiceProviderInterface as PimpleServiceProviderInterface;
    
    class MyServiceProvider implements ServiceProviderInterface
    {
        public function register(Container $container)
        {
            $container['my_service'] = function () {
                return new MyService();
            };
        }
    }
    
  4. Register the provider in your test class:
    protected function getServiceProviders()
    {
        return [
            MyServiceProvider::class,
        ];
    }
    
  5. Access services in tests:
    public function testSomething()
    {
        $service = $this->getService('my_service');
        // Use $service in assertions
    }
    

First Use Case

Mock external dependencies (e.g., databases, APIs) by registering mock implementations in providers. Example:

class DatabaseServiceProvider implements ServiceProviderInterface
{
    public function register(Container $container)
    {
        $container['db'] = function () {
            return $this->createMock(Database::class);
        };
    }
}

Implementation Patterns

Common Workflows

  1. Isolated Test Dependencies:

    • Use providers to define test-specific implementations (e.g., mocks, stubs) without polluting global container.
    • Example: Database, HTTP clients, or third-party APIs.
    $container['http_client'] = function () {
        return $this->createMock(GuzzleClient::class);
    };
    
  2. Shared Test State:

    • Register reusable test data or configurations in providers.
    $container['test_user'] = function () {
        return User::factory()->create(['name' => 'Test User']);
    };
    
  3. Dependency Chaining:

    • Chain service definitions to build complex test objects.
    $container['user_repository'] = function ($c) {
        return new UserRepository($c['db'], $c['test_user']);
    };
    
  4. Dynamic Service Resolution:

    • Use closures to lazy-load services (e.g., for expensive setup).
    $container['expensive_service'] = function () {
        return new ExpensiveService(config('test.expensive_config'));
    };
    

Integration Tips

  • Laravel Integration:
    • Use the container to override Laravel’s DI for tests:
      $container['app'] = function ($c) {
          $app = new Illuminate\Foundation\Application();
          $app->bind('db', function () use ($c) {
              return $c['db']; // Your mock DB
          });
          return $app;
      };
      
  • Configuration:
    • Load test-specific configs via providers:
      $container['config'] = function () {
          return require __DIR__.'/test_config.php';
      };
      
  • Test Suites:
    • Group providers by test suite (e.g., UserTestProvider, PaymentTestProvider) for modularity.

Gotchas and Tips

Pitfalls

  1. Service Overrides:

    • Avoid redefining the same service in multiple providers. The last registration wins.
    • Fix: Use unique keys or merge providers carefully.
  2. Circular Dependencies:

    • Pimple throws exceptions for circular references. Debug by simplifying provider logic.
    • Tip: Use container->offsetExists() to check for existing services before binding.
  3. Stateful Services:

    • Services registered as singletons retain state across tests. Reset them in setUp():
      public function setUp(): void
      {
          $this->getService('stateful_service')->reset();
      }
      
  4. Provider Order:

    • Providers are registered in the order returned by getServiceProviders(). Depend on explicit ordering or use dependency injection within providers.

Debugging

  • Inspect Container:
    $this->getContainer()->keys(); // List all registered services
    $this->getContainer()->offsetGet('service_name'); // Inspect a service
    
  • Enable Pimple Debug:
    $container->debug = true; // Logs service resolution
    

Extension Points

  1. Custom Base Test Case:

    • Extend TestCase to add default providers or pre-configured services:
      class BaseTest extends TestCase
      {
          protected function getServiceProviders()
          {
              return [
                  CommonTestProvider::class,
                  parent::getServiceProviders(),
              ];
          }
      }
      
  2. Dynamic Providers:

    • Load providers conditionally (e.g., based on environment or test class):
      protected function getServiceProviders()
      {
          return array_merge(
              [CommonProvider::class],
              $this->shouldUseSpecialProvider() ? [SpecialProvider::class] : []
          );
      }
      
  3. Service Factories:

    • Use factories for complex service setup:
      $container['user_factory'] = function () {
          return User::factory();
      };
      

Config Quirks

  • Pimple Version:
    • The package uses Pimple v3. Verify compatibility with your project’s Pimple usage (e.g., offsetGet vs get).
  • Thread Safety:
    • The container is not thread-safe. Avoid sharing it across test processes (e.g., parallel tests).
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky