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

Testbench Core Laravel Package

graham-campbell/testbench-core

Core testing utilities for Laravel packages, maintained by Graham Campbell. Provides lightweight TestBench components compatible with Laravel 8–13, PHP 7.4–8.5, and PHPUnit 9–12 to simplify package test setup and integration.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev graham-campbell/testbench-core:^4.3
    
    • No configuration required; the package provides zero-dependency traits for testing.
  2. First Use Case: Extend your test class with Illuminate\Foundation\Testing\TestCase (Laravel’s base test case) and add the desired trait (e.g., MockeryTrait or ServiceProviderTrait). Example:

    use GrahamCampbell\TestbenchCore\Traits\MockeryTrait;
    use Illuminate\Foundation\Testing\TestCase;
    
    class UserTest extends TestCase
    {
        use MockeryTrait;
    
        public function test_mocked_service()
        {
            $mock = $this->mock('App\Services\UserService');
            $mock->shouldReceive('fetchUser')->once()->andReturn(['id' => 1]);
    
            $this->assertEquals(['id' => 1], $mock->fetchUser());
        }
    }
    
  3. Where to Look First:

    • Traits: Focus on MockeryTrait, FacadeTrait, and ServiceProviderTrait for core testing needs.
    • Changelog: Review V4.x for breaking changes (e.g., static methods in V4.0).
    • Laravel TestBench Docs: Pair with Laravel’s official testing docs for integration patterns.

Implementation Patterns

Core Workflows

  1. Mocking Services: Use MockeryTrait to mock Laravel services, repositories, or external APIs.

    $mock = $this->mock('App\Contracts\UserRepository');
    $mock->shouldReceive('findById')->with(1)->andReturn(new User());
    
    • Pattern: Prefer mock() over partialMock() for strict contract testing.
  2. Testing Facades: Leverage FacadeTrait to verify facade interactions without instantiating underlying classes.

    $this->assertEquals('expected', Facade::getFacadeRoot()->method());
    
    • Pattern: Use getFacadeAccessor() to inspect bound services directly.
  3. Service Provider Testing: Extend ServiceProviderTrait to test bindings, boot methods, and registrations.

    $provider = new MyServiceProvider($this->app);
    $this->assertTrue($provider->registers('binding'));
    
    • Pattern: Combine with MockeryTrait to stub dependencies in providers.
  4. Assertions: Use Laravel-specific assertions like assertArraySubset or assertInternalType.

    $this->assertArraySubset(['id' => 1], $user->toArray());
    $this->assertInternalType('array', $response->json());
    

Integration Tips

  • TestCase Setup: Override createApplication() in your test class to bootstrap Laravel with custom config/testing environments.

    protected function createApplication()
    {
        $app = require __DIR__.'/../../bootstrap/app.php';
        $app->make(Kernel::class)->bootstrap();
        return $app;
    }
    
  • Database Testing: Use Laravel’s built-in RefreshDatabase trait alongside TestBench Core for seamless DB-driven tests.

    use Illuminate\Foundation\Testing\RefreshDatabase;
    
    class UserTest extends TestCase
    {
        use RefreshDatabase, MockeryTrait;
        // ...
    }
    
  • HTTP Testing: Combine with Laravel’s HttpTests trait for API/route testing.

    use Illuminate\Foundation\Testing\Concerns\InteractsWithHttp;
    
    class UserApiTest extends TestCase
    {
        use InteractsWithHttp, MockeryTrait;
        // ...
    }
    
  • Custom Traits: Extend TestBench Core traits to add project-specific helpers.

    trait CustomAssertions
    {
        public function assertResponseHasError(array $expectedErrors)
        {
            $response = $this->response;
            $this->assertArraySubset($expectedErrors, $response->json()['errors']);
        }
    }
    

Gotchas and Tips

Pitfalls

  1. Mockery Deprecation:

    • Issue: MockeryTrait may trigger deprecation warnings in PHPUnit 12+ (fixed in V4.2.1).
    • Fix: Update to ^4.2.1 or suppress warnings if using older versions.
      $mock = $this->mock('Class', [], [], false, false, true, false);
      
  2. Static Method Changes (V4.0+):

    • Issue: Methods like getFacadeAccessor() became static in V4.0, breaking older code.
    • Fix: Update calls to use the class name:
      // Old (pre-V4.0)
      $this->getFacadeAccessor();
      
      // New (V4.0+)
      FacadeTrait::getFacadeAccessor();
      
  3. PHPUnit Version Mismatch:

    • Issue: PHPUnit 13 is unsupported due to volatility. Tests may fail with cryptic errors.
    • Fix: Pin to PHPUnit 12 in composer.json:
      "require-dev": {
          "phpunit/phpunit": "^12.0"
      }
      
  4. Service Provider Traits:

    • Issue: getServiceProviderClass() no longer accepts $app as a parameter (V4.0+).
    • Fix: Pass the class name directly:
      // Old
      $providerClass = $this->getServiceProviderClass($app, 'App\Providers\MyProvider');
      
      // New
      $providerClass = ServiceProviderTrait::getServiceProviderClass('App\Providers\MyProvider');
      
  5. Facade Root Access:

    • Issue: getFacadeRoot() may return null if the facade isn’t bound.
    • Fix: Add null checks:
      $root = FacadeTrait::getFacadeRoot();
      $this->assertNotNull($root, 'Facade not bound');
      

Debugging Tips

  • Mockery Debugging: Enable Mockery’s verbose output to diagnose stubbing issues:

    Mockery::getConfiguration()->setVerbose(true);
    
  • Service Container Dumps: Inspect bindings with:

    $this->app->bindings();
    
  • Test Isolation: Use setUp() and tearDown() to reset state between tests:

    protected function tearDown(): void
    {
        Mockery::close();
        parent::tearDown();
    }
    

Extension Points

  1. Custom Traits: Create project-specific traits by extending TestBench Core’s base traits. Example:

    trait ApiResponseAssertions
    {
        use MockeryTrait;
    
        public function assertApiSuccess($response, $expectedData = [])
        {
            $this->assertEquals(200, $response->status());
            $this->assertArraySubset($expectedData, $response->json());
        }
    }
    
  2. Test Helpers: Add static helper methods to your test base class:

    abstract class BaseTestCase extends TestCase
    {
        protected static function createTestUser()
        {
            return User::factory()->create(['email' => 'test@example.com']);
        }
    }
    
  3. Test Data Factories: Combine with Laravel’s factories for realistic test data:

    $user = User::factory()->create();
    $this->mock('App\Services\AuthService')
         ->shouldReceive('getUser')
         ->andReturn($user);
    
  4. Parallel Testing: Use PHPUnit’s --parallel flag with TestBench Core for faster test suites:

    vendor/bin/phpunit --parallel
    
    • Note: Ensure tests are stateless (e.g., avoid shared DB state).

Performance Tips

  • Mock Sparingly: Avoid over-mocking; prefer real implementations for performance-critical tests.
  • Lazy Loading: Defer heavy mock setups until setUp() to reduce test initialization time.
  • Selective Assertions: Use assertArraySubset instead of assertEquals for large arrays to skip deep comparisons.
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.
davejamesmiller/laravel-breadcrumbs
artisanry/parsedown
christhompsontldr/phpsdk
enqueue/dsn
bunny/bunny
enqueue/test
enqueue/null
enqueue/amqp-tools
milesj/emojibase
bower-asset/punycode
bower-asset/inputmask
bower-asset/jquery
bower-asset/yii2-pjax
laravel/nova
spatie/laravel-mailcoach
spatie/laravel-superseeder
laravel/liferaft
nst/json-test-suite
danielmiessler/sec-lists
jackalope/jackalope-transport