SyntaxStudy
Sign Up
Laravel Feature Testing with PHPUnit in Laravel
Laravel Beginner 1 min read

Feature Testing with PHPUnit in Laravel

Laravel is built with testing in mind. It includes PHPUnit out of the box and provides a rich set of testing helpers via the TestCase base class in Illuminate\Foundation\Testing. Feature tests simulate HTTP requests and test the full application stack — routing, middleware, controllers, and database. They are the most common type of test in a Laravel application and live in the tests/Feature directory. The $this->get(), $this->post(), $this->put(), and $this->delete() methods simulate HTTP requests and return a TestResponse instance. TestResponse provides assertion methods like assertStatus(), assertOk(), assertJson(), assertRedirect(), assertSee(), and assertDatabaseHas(). These assertions cover the most common checks: response codes, JSON content, redirects, rendered HTML, and database state. The RefreshDatabase trait resets the database between tests using transactions (for SQLite and MySQL with transactions), keeping tests isolated and fast. The DatabaseMigrations trait runs full migrations before each test and rolls them back after, which is slower but required when testing migrations themselves. Using factories to create test data ensures deterministic, readable test setup without raw SQL inserts.
Example
<?php
// tests/Feature/PostTest.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;

    public function test_authenticated_user_can_view_post_list(): void
    {
        $user = User::factory()->create();
        Post::factory(5)->published()->for($user)->create();

        $response = $this->actingAs($user)->get('/posts');

        $response->assertOk()
                 ->assertViewIs('posts.index')
                 ->assertViewHas('posts');
    }

    public function test_guest_cannot_create_a_post(): void
    {
        $response = $this->post('/posts', ['title' => 'Test', 'body' => str_repeat('a', 50)]);
        $response->assertRedirect('/login');
    }

    public function test_user_can_create_a_post(): void
    {
        $user = User::factory()->create();

        $response = $this->actingAs($user)->post('/posts', [
            'title'       => 'My First Post',
            'slug'        => 'my-first-post',
            'body'        => str_repeat('Hello world ', 10),
            'status'      => 'published',
            'category_id' => 1,
        ]);

        $response->assertRedirect();
        $this->assertDatabaseHas('posts', ['slug' => 'my-first-post']);
    }
}