orchestra/testbench-core
Testbench Core is the foundation for Orchestra Testbench, providing a lightweight Laravel application bootstrap for package testing. Run artisan commands, migrations, factories, and routes in your test suite with versioned Laravel compatibility.
Installation:
composer require --dev orchestra/testbench-core
Ensure version compatibility with your Laravel version (e.g., Laravel 12.x → Testbench Core 10.x).
Basic Test Structure:
Create a test class extending Orchestra\Testbench\TestCase (or Orchestra\Testbench\PHPUnit\TestCase for PHPUnit):
use Orchestra\Testbench\TestCase;
class ExampleTest extends TestCase
{
public function test_basic()
{
$this->assertTrue(true);
}
}
First Use Case: Test a package's service provider registration:
public function test_service_provider_registration()
{
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
$this->assertTrue($this->app->has('MyServiceProvider'));
}
setUp(): Override to configure the test environment (e.g., load migrations, bind services).getPackageProviders(): Define package providers for testing:
protected function getPackageProviders($app)
{
return ['MyPackage\\Providers\\MyServiceProvider'];
}
getEnvironmentSetUp(): Configure environment (e.g., database, queues):
protected function getEnvironmentSetUp($app)
{
$app['config']->set('database.default', 'sqlite_memory');
}
Testing Service Providers:
public function test_provider_boot()
{
$this->assertTrue($this->app->bound('my.bound.service'));
}
Testing Artisan Commands:
Use Artisan::call() or Artisan::assertExitCode():
public function test_custom_command()
{
Artisan::call('my:command', ['option' => 'value']);
$this->assertStringContainsString('Success', Artisan::output());
}
Testing Migrations:
Load migrations in setUp() and assert schema:
public function test_migration()
{
$this->loadMigrationsFrom(__DIR__.'/../database/migrations');
$this->assertDatabaseHas('table_name', ['column' => 'value']);
}
Testing Routes:
Use get() or post() with TestResponse:
public function test_route()
{
$response = $this->get('/api/endpoint');
$response->assertStatus(200);
}
Testing Middleware:
Override getMiddlewareGroups() or getMiddleware():
protected function getMiddlewareGroups($middlewareGroups)
{
return array_merge(parent::getMiddlewareGroups($middlewareGroups), [
'web' => ['App\Http\Middleware\MyMiddleware'],
]);
}
Mocking Dependencies:
Use Mockery (included via InteractsWithMockery trait):
$mock = Mockery::mock('App\Contracts\MyContract');
$this->app->instance('App\Contracts\MyContract', $mock);
Testing Events:
Use Events::assertDispatched():
Events::assertDispatched(MyEvent::class);
Testing Jobs/Queues:
Use Queue::fake() and Queue::assertPushed():
Queue::fake();
MyJob::dispatch();
Queue::assertPushed(MyJob::class);
Testing API Resources:
Use JsonResource assertions:
$response = $this->getJson('/api/resource');
$response->assertJsonStructure(['data' => ['id', 'name']]);
Parallel Testing:
Configure testbench.yaml for parallel runs:
seeders: true
Custom Skeleton:
Extend Orchestra\Testbench\Skeleton\Skeleton to override default Laravel setup.
Remote Testing:
Use Orchestra\Testbench\remote() for cross-package testing:
$result = remote(function () {
return app()->version();
});
Fixtures:
Use WithFixtures trait to load test data:
use Orchestra\Testbench\Concerns\WithFixtures;
public function test_with_fixtures()
{
$this->loadFixtures(['users']);
$this->assertDatabaseHas('users', ['email' => 'test@example.com']);
}
Database Rollbacks:
refreshDatabase() or refreshMigrations() in setUp():
public function setUp(): void
{
parent::setUp();
$this->refreshDatabase();
}
Service Provider Loading:
getPackageProviders().protected function getPackageProviders($app)
{
return ['Vendor\\Package\\Providers\\ServiceProvider'];
}
Environment Configuration:
.env settings.getEnvironmentSetUp():
$app['config']->set('app.debug', false);
Mockery vs. PHPUnit:
Mockery and PHPUnit mocks.Mockery::close() in tearDown():
public function tearDown(): void
{
Mockery::close();
parent::tearDown();
}
Parallel Testing:
testbench.yaml:
seeders: false # Disable if using custom fixtures
Artisan Command Output:
Artisan::call() may not capture output correctly.Artisan::output() or expectsOutput():
Artisan::call('command', ['--option' => 'value']);
$this->assertStringContainsString('Expected', Artisan::output());
Enable Debug Mode:
Set APP_DEBUG=true in getEnvironmentSetUp() for verbose errors.
Log Test Output:
Use dd() or dump() sparingly; prefer assert methods.
Isolate Tests: Avoid shared state between tests (e.g., static variables, global configs).
Check for Deprecations:
Use Orchestra\Testbench\terminate() or bail() to exit tests early if needed.
testbench.yaml:
seeders: true: Runs database seeders before tests.parallel: true: Enables parallel test execution (requires PHPUnit 9+).Custom Skeleton:
Orchestra\Testbench\Skeleton\Skeleton to modify Laravel’s default setup.protected function configureSkeleton(Skeleton $skeleton)
{
$skeleton->withoutDefaultProviders();
}
Terminating Console:
ServeCommand to use TerminatingConsole for better test isolation.Custom Assertions:
Extend Orchestra\Testbench\TestCase to add domain-specific assertions.
Test Traits:
Create reusable traits for common test logic (e.g., WithCustomFixtures).
Remote Testing:
Use Orchestra\Testbench\remote() to test packages in isolation.
PestPHP Support:
Testbench Core supports PestPHP via testbench.yaml configuration:
pest: true
Flushing States:
Manually flush Laravel states (e.g., Str, Validator) in tearDown():
public function tearDown(): void
{
\Illuminate\Support\Str::flushStates();
parent::tearDown();
}
WithFixtures for complex test data setup.package_version_compare() to test version-specific behavior.$skeleton->withoutDefaultProviders();
Orchestra\Testbench\bail() to handle unrecoverable failures in parallel tests.How can I help you explore Laravel packages today?