orchestra/testbench
Orchestra Testbench is the de-facto Laravel testing helper for package development. It boots a lightweight Laravel app for your package’s tests, making it easy to run PHPUnit/Pest suites with proper service providers, config, and environment setup.
Installation:
composer require --dev orchestra/testbench
Add to your composer.json under require-dev:
"orchestra/testbench": "^11.0"
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 service provider by overriding getPackageProviders():
protected function getPackageProviders($app)
{
return ['YourPackage\\ServiceProvider'];
}
tests/TestCase.php in your package for base test configuration.testbench.yaml (optional) for global test configurations like database, seeders, or environment.getPackageProviders() to load your package’s providers.protected function getPackageProviders($app)
{
return [
\YourPackage\Providers\AuthServiceProvider::class,
\YourPackage\Providers\RouteServiceProvider::class,
];
}
getEnvironmentSetUp() to modify the app environment before booting providers.WithFixtures trait to load test data.use Orchestra\Testbench\Concerns\WithFixtures;
class UserTest extends TestCase
{
use WithFixtures;
protected function getFixturesPath()
{
return __DIR__ . '/fixtures';
}
public function test_user_creation()
{
$user = User::factory()->create();
$this->assertDatabaseHas('users', ['email' => $user->email]);
}
}
testbench.yaml to auto-run seeders:
seeders: true
InteractsWithMockery (included in TestCase).public function test_mocked_service()
{
$mock = Mockery::mock('overload:YourPackage\\Services\\UserService');
$mock->shouldReceive('fetchUser')->andReturn(['id' => 1]);
$result = app()->make('YourPackage\\Services\\UserService')->fetchUser();
$this->assertEquals(['id' => 1], $result);
}
public function test_api_route()
{
$response = $this->getJson('/api/endpoint');
$response->assertStatus(200)
->assertJson(['key' => 'value']);
}
getPackageAliases() to alias your package’s Facades for cleaner tests.public function test_config_published()
{
$this->publishes([
__DIR__.'/../config/your-package.php' => config_path('your-package.php'),
], 'config');
$this->assertArrayHasKey('key', config('your-package'));
}
--parallel flag with PHPUnit.WithFixtures is compatible (fixed in v10.11.0+).phpunit --parallel
Orchestra\Testbench\uses_default_skeleton() to check if the default skeleton is used.getEnvironmentSetUp() to customize the app environment:
protected function getEnvironmentSetUp($app)
{
$app['config']->set('your-package.key', 'test-value');
}
public function test_artisan_command()
{
$this->artisan('your-package:command')
->expectsOutput('Command output')
->assertExitCode(0);
}
$this->assertTrue(\Orchestra\Testbench\package_version_compare('1.0.0', '1.0.0', '>='));
Str, Validator, Model):
public function tearDown(): void
{
parent::tearDown();
\Orchestra\Testbench\flushState();
}
Deprecated Annotations:
@define-env, @environment-setup, @define-db, and @define-route (removed in v11.0.0).getEnvironmentSetUp() or testbench.yaml instead.Parallel Testing Issues:
WithFixtures may fail in parallel mode (fixed in v10.11.0+).State Persistence:
Str::macro(), Validator rules) persist between tests unless flushed.flushState() in tearDown() or use Orchestra\Testbench\flushState() globally.BindingResolutionException:
#[UsesVendor] is used before the app is booted.SQLite Journal Files:
testbench.yaml to remove them:
database:
journal_mode: DELETE
PHPUnit 13+ Compatibility:
^11.0 for PHPUnit 13).Environment Variables:
TESTBENCH_ENVIRONMENT_FILE to specify a custom .env file:
TESTBENCH_ENVIRONMENT_FILE=.env.testing phpunit
Logging:
testbench.yaml:
logging:
enabled: true
level: debug
Isolation Issues:
public function tearDown(): void
{
$this->refreshApplication();
parent::tearDown();
}
Mockery Warnings:
Mockery::close();
Custom TestCase:
Orchestra\Testbench\PHPUnit\TestCase to add reusable methods:
class PackageTestCase extends \Orchestra\Testbench\PHPUnit\TestCase
{
protected function assertPackageConfig($key, $expected)
{
$this->assertEquals($expected, config("your-package.$key"));
}
}
Dynamic Providers:
protected function getPackageProviders($app)
{
return config('your-package.enabled') ? ['YourPackage\\ServiceProvider'] : [];
}
Custom Assertions:
protected function assertRouteExists($uri)
{
$this->assertTrue(Route::has($uri));
}
Testbench YAML:
database:
connection: sqlite
migrations: true
seeders: true
environment:
APP_ENV: testing
PestPHP Support:
$__filename to resolve test file paths:
use Orchestra\Testbench\Concerns\InteractsWithFixtures;
test('example', function () {
$this->loadFixturesFrom($__
How can I help you explore Laravel packages today?