Pest is the testing framework I wish existed when I started with Laravel. It's PHPUnit under the hood, but the expressive syntax makes tests a pleasure to read and write.
Why Pest Over PHPUnit Directly
Pest tests read like documentation:
// PHPUnit
public function test_published_posts_are_visible(): void
{
$post = Post::factory()->published()->create();
$response = $this->get('/writing');
$response->assertStatus(200);
$response->assertSee($post->title);
}
// Pest
it('shows published posts on the writing page', function () {
$post = Post::factory()->published()->create();
get('/writing')
->assertOk()
->assertSee($post->title);
});
Test Structure I Use
tests/
Feature/
Site/
WritingTest.php -- public reading experience
AiChatTest.php -- AI playground
Admin/
PostsTest.php -- CRUD admin flows
Unit/
SlugServiceTest.php
Database Strategy
I use RefreshDatabase for feature tests but LazilyRefreshDatabase in suites that don't modify the DB. For read-heavy tests, seeding once per suite saves significant time:
beforeAll(function () {
Post::factory(20)->published()->create();
Post::factory(5)->draft()->create();
});
it('paginates at 10 posts', function () {
get('/writing')->assertSee('Newer');
});
Testing Auth Flows
it('redirects guests away from admin', function () {
get('/admin/posts')->assertRedirect('/login');
});
it('allows admins to create posts', function () {
$admin = User::factory()->admin()->create();
actingAs($admin)
->post('/admin/posts', Post::factory()->make()->toArray())
->assertRedirect();
expect(Post::count())->toBe(1);
});
Datasets for Edge Cases
dataset('invalid slugs', [
'empty string' => [''],
'only spaces' => [' '],
'too long' => [str_repeat('a', 256)],
]);
it('rejects invalid slugs', function (string $slug) {
actingAs(User::factory()->admin()->create())
->post('/admin/posts', ['slug' => $slug])
->assertInvalid('slug');
})->with('invalid slugs');
A
Al Amin Ahamed
Senior software engineer & AI practitioner. Building things in Laravel, PHP, and TypeScript.
About me →← Older
Five Years of Open Source on WordPress.org — What I've Learned
Newer →
WP-CLI Tips That Actually Save Time
One email a month. No noise.
What I shipped, what I read, occasional deep dive. Unsubscribe anytime.