graham-campbell/testbench
Testing utilities for Laravel packages, built on PHPUnit, Mockery, Orchestral Testbench, and Laravel Testbench Core. Supports Laravel 8–13 and PHP 7.4–8.5, with compatibility for PHPUnit 9–11 to help you run fast, reliable package test suites.
Installation:
composer require --dev graham-campbell/testbench:^6.3
No additional configuration is required—TestBench integrates seamlessly with Laravel’s testing ecosystem.
First Test Case:
Extend GrahamCampbell\TestBench\AbstractPackageTestCase for package tests or GrahamCampbell\TestBench\AbstractAppTestCase for application tests.
use GrahamCampbell\TestBench\AbstractPackageTestCase;
class ExampleTest extends AbstractPackageTestCase
{
protected function getPackageProviders($app)
{
return ['YourPackage\\ServiceProvider'];
}
public function test_example()
{
$this->assertTrue(true);
}
}
Key Entry Points:
getPackageProviders(): Define providers to load in tests.getEnvironmentSetUp($app): Customize app bootstrapping (e.g., config, migrations).getBasePath(): Override for custom package paths (static in v6+).Package Testing:
AbstractPackageTestCase to test isolated package functionality.public function test_service_registered()
{
$this->assertTrue($this->app->bound('your-package-service'));
}
Application Testing:
AbstractAppTestCase for full Laravel app tests (e.g., HTTP routes, jobs).actingAs(), assertJson()).public function test_route_handling()
{
$response = $this->get('/api/endpoint');
$response->assertStatus(200);
}
Database Testing:
createApplication() with $app->loadMigrationsFrom() to set up a test database.protected function getEnvironmentSetUp($app)
{
$app->make(Kernel::class)->bootstrap();
$app['db']->connection()->getSchemaBuilder()->create('test_table', function ($table) {
$table->id();
});
}
Mocking Services:
$mock = Mockery::mock('alias:YourService');
$mock->shouldReceive('method')->once();
phpunit.xml to parallelize tests:
<phpunit>
<extensions>
<extension class="GrahamCampbell\TestBench\PHPUnit\ParallelExtension"/>
</extensions>
</phpunit>
AbstractTestCase to add domain-specific assertions.getPackageProviders() or getApplicationProviders().Static Methods in v6+:
getBasePath() and getRequiredServiceProviders() are now static. Avoid passing $app as an argument (breaks in v6+).// ❌ Old (v5.x)
protected function getRequiredServiceProviders($app) { ... }
// ✅ New (v6.x)
protected static function getRequiredServiceProviders() { ... }
PHPUnit 12 Quirks:
orchestral/testbench is pinned to ^6.0 (TestBench v6.3+ handles this).Database Transactions:
public function test_with_side_effects()
{
$this->withoutExceptionHandling();
// Test logic...
}
Encryption Key:
base64:...). For encryption-heavy tests, override in getEnvironmentSetUp():$app['config']['app.key'] = 'test-key-here';
Xdebug or --debug flag to profile bottlenecks (e.g., migrations, service resolution).shouldReceive() or shouldNotReceive() to avoid silent failures.getPackageProviders() for typos or missing dependencies.Custom Test Cases:
abstract class BaseTestCase extends AbstractPackageTestCase
{
protected function setUp(): void
{
parent::setUp();
// Shared setup (e.g., seed test data).
}
}
Test Data Factories:
public function test_user_creation()
{
$user = User::factory()->create();
$this->assertDatabaseHas('users', ['email' => $user->email]);
}
Parallel Testing:
phpunit.xml (requires PHPUnit 9+):<phpunit parallel="true" parallelConfig="phpunit.parallel.xml">
<server name="DB_DATABASE" value="testbench_parallel"/>
</phpunit>
phpunit.parallel.xml to define database connections per worker.Event Testing:
expectsEvents():Event::fake();
$this->app['events']->dispatch(new YourEvent());
Event::assertDispatched(YourEvent::class);
How can I help you explore Laravel packages today?