nette/tester
Nette Tester is a lightweight PHP testing framework for unit tests and test suites. It offers simple assertions, data-driven tests, informative output, and easy CLI integration. Ideal for fast, reliable testing in PHP projects and CI pipelines.
Installation:
composer require nette/tester --dev
Add to composer.json under require-dev:
"autoload-dev": {
"psr-4": {
"Tests\\": "tests/"
}
}
First Test File:
Create tests/MyTest.php:
<?php
use Tester\TestCase;
class MyTest extends TestCase
{
public function testBasicAssertion()
{
$this->test(1 + 1 === 2);
}
}
Run Tests:
vendor/bin/tester tests/MyTest.php
public function testLaravelSpecific()
{
$response = new \Illuminate\Http\Response('Hello');
$this->test($response->getContent() === 'Hello');
$this->test($response->getStatusCode() === 200);
$this->testException(function () {
throw new \RuntimeException('Expected error');
}, 'RuntimeException');
}
Laravel Integration Pattern:
class UserTest extends TestCase
{
protected function setUp(): void
{
parent::setUp();
$this->app = require __DIR__.'/../bootstrap/app.php';
$this->app->make(\Illuminate\Contracts\Http\Kernel::class)->bootstrap();
}
public function testUserCreation()
{
$user = \App\Models\User::factory()->create();
$this->test($user->exists);
$this->test($user->email !== null);
}
}
public function providerUserRoles()
{
return [
['admin', 'Administrator'],
['user', 'Regular User'],
];
}
public function testUserRoles($role, $description)
{
$user = \App\Models\User::factory()->create(['role' => $role]);
$this->test($user->role === $role);
$this->test($user->description === $description);
}
public function testGetUser()
{
$response = $this->get('/api/user/1');
$this->test($response->getStatusCode() === 200);
$this->test($response->json()['id'] === 1);
}
protected function setUp(): void
{
parent::setUp();
$this->beginDatabaseTransaction();
}
protected function tearDown(): void
{
$this->rollbackDatabaseTransaction();
parent::tearDown();
}
vendor/bin/tester tests/ --parallel
System php.ini Usage:
php.ini by default. Use -C flag to override:
vendor/bin/tester tests/ -C /path/to/custom/php.ini
Test Lifecycle:
tearDown() runs even when tests fail (since v2.6.0). Avoid side effects in assertions.Assertion Order:
Assert::equal() with $matchOrder = true can cause false positives if array order matters.Parallel Execution:
Verbose Output:
vendor/bin/tester tests/ -v
Console Lines Mode:
vendor/bin/tester tests/ --console-lines
Dumper Integration:
$this->dump($this->app->make(\App\Models\User::class));
Error Output Capture:
$this->testException(function () {
// Code that might fail
}, 'RuntimeException', 'Expected error message');
Custom Assertions:
$this->assertDatabaseHas('users', ['email' => 'test@example.com']);
Test Templates:
Extend TestCase for shared setup:
abstract class LaravelTestCase extends TestCase
{
protected $app;
protected function setUp(): void
{
$this->app = require __DIR__.'/../../bootstrap/app.php';
$this->app->make(\Illuminate\Contracts\Http\Kernel::class)->bootstrap();
}
}
Code Coverage:
vendor/bin/tester tests/ --coverage
Custom Output Formats:
vendor/bin/tester tests/ --format=junit
Service Container:
app() helper or $this->app->make() instead of direct instantiation.Artisan Commands:
$this->artisan('migrate:fresh')
->expectsQuestion('confirm', 'yes')
->assertExitCode(0);
Event Testing:
$this->app->make(\Illuminate\Contracts\Events\Dispatcher::class)
->listen('user.created', function () {
// Assert event was fired
});
Queue Testing:
$this->app->make(\Illuminate\Contracts\Queue\Factory::class)
->fake()
->assertPushed(\App\Jobs\SendEmail::class);
How can I help you explore Laravel packages today?