Testing in Laravel
LaravelTesting ensures your code works correctly and prevents bugs from reappearing. Laravel has excellent built-in testing support with PHPUnit and Pest.
Types of Tests
| Type | Tests | Speed |
|---|---|---|
| Unit | Single class/method in isolation | Very fast |
| Feature | Full HTTP request/response cycle | Medium |
| Browser (Dusk) | Real browser interaction | Slow |
Running Tests
Terminal
# Run all tests
php artisan test
# Run specific test file
php artisan test tests/Feature/PostTest.php
# Run specific test method
php artisan test --filter=test_user_can_create_post
# Run with coverage
php artisan test --coverageFeature Test — API Endpoint
tests/Feature/PostTest.php
<?php
namespace Tests\Feature;
use App\Models\Post;
use App\Models\User;
use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;
class PostTest extends TestCase
{
use RefreshDatabase; // Fresh DB for each test
public function test_user_can_get_all_posts(): void
{
Post::factory(5)->create();
$response = $this->getJson('/api/posts');
$response
->assertStatus(200)
->assertJsonCount(5, 'data')
->assertJsonStructure([
'data' => [['id', 'title', 'body', 'author']]
]);
}
public function test_authenticated_user_can_create_post(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user, 'sanctum')
->postJson('/api/posts', [
'title' => 'My Test Post',
'body' => 'This is the post body content.',
]);
$response->assertStatus(201);
$this->assertDatabaseHas('posts', [
'title' => 'My Test Post',
'user_id' => $user->id,
]);
}
public function test_unauthenticated_user_cannot_create_post(): void
{
$response = $this->postJson('/api/posts', [
'title' => 'Test',
'body' => 'Body',
]);
$response->assertStatus(401);
}
public function test_post_requires_title(): void
{
$user = User::factory()->create();
$response = $this->actingAs($user, 'sanctum')
->postJson('/api/posts', ['body' => 'No title']);
$response
->assertStatus(422)
->assertJsonValidationErrors(['title']);
}
}Unit Test
tests/Unit/PostTest.php
<?php
class PostTest extends TestCase
{
public function test_post_can_generate_excerpt(): void
{
$post = new Post(['body' => 'This is a very long post body...']);
$this->assertEquals('This is a very long...', $post->excerpt(20));
}
public function test_post_slug_is_generated_from_title(): void
{
$post = Post::factory()->make(['title' => 'Hello World Post']);
$this->assertEquals('hello-world-post', $post->slug);
}
}Factories
database/factories/PostFactory.php
<?php
class PostFactory extends Factory
{
public function definition(): array
{
return [
'user_id' => User::factory(),
'title' => fake()->sentence(),
'slug' => fake()->slug(),
'body' => fake()->paragraphs(3, true),
'published' => fake()->boolean(70), // 70% chance true
'views' => fake()->numberBetween(0, 10000),
];
}
// State modifier
public function published(): static
{
return $this->state(['published' => true]);
}
}
// Usage in tests
Post::factory(10)->create();
Post::factory()->published()->create();
Post::factory(5)->for($user)->create();💡
Write tests as you code! At your company (ms-cms), tests would catch bugs before they reach production. Even basic feature tests for your main API endpoints can save hours of debugging.
Test your knowledge!
Take the Laravel quiz.