Testing Laravel Applications with PHPUnit

Testing Laravel Applications with PHPUnit

Testing Laravel Applications with PHPUnit

Testing is essential for building reliable, maintainable Laravel applications. With PHPUnit integrated out of the box, you can write unit and feature tests that validate your business logic, HTTP flows, and database interactions. This guide walks through setup, writing your first tests, and understanding typical test outputs.

Setting Up PHPUnit in Laravel

Laravel ships with PHPUnit preconfigured in composer.json under require-dev. Confirm the dependency and install vendor packages.

"require-dev": {
    "phpunit/phpunit": "^10.0"
}Code language: JSON / JSON with Comments (json)

This ensures PHPUnit is available to Laravel’s test runner. If you’re upgrading, run composer update to get the right version for your PHP/Laravel stack.

composer install
php artisan testCode language: Bash (bash)

The first run should execute the default example test and report results in a readable, colored format.

Creating Your First Unit Test

Use Artisan to scaffold a unit test class. Unit tests focus on small, isolated pieces of logic without the framework bootstrapping overhead.

php artisan make:test UserMathTest --unitCode language: Bash (bash)

Open the generated file at tests/Unit/UserMathTest.php and add a simple assertion.

namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class UserMathTest extends TestCase
{
    public function test_basic_math_addition()
    {
        $this->assertSame(4, 2 + 2);
    }
}Code language: PHP (php)

This basic test verifies your PHPUnit setup. It runs quickly and proves your environment is configured correctly.

Writing a Feature Test (HTTP + Database)

Feature tests exercise full request lifecycles, including routes, controllers, middleware, and the database. Let’s test a simple “create post” flow.

php artisan make:test PostCreationTestCode language: Bash (bash)

Update tests/Feature/PostCreationTest.php to validate the HTTP response and database changes.

namespace Tests\Feature;

use Tests\TestCase;
use Illuminate\Foundation\Testing\RefreshDatabase;
use App\Models\User;
use App\Models\Post;

class PostCreationTest extends TestCase
{
    use RefreshDatabase;

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

        $response = $this->actingAs($user)
            ->post('/posts', [
                'title' => 'My First Post',
                'body'  => 'Hello world!',
            ]);

        $response->assertRedirect('/posts');
        $this->assertDatabaseHas('posts', [
            'title' => 'My First Post',
        ]);
    }
}Code language: PHP (php)

This test signs in a user, posts form data, expects a redirect, and verifies that the record exists. For production-grade examples of auth flows, also see How to Build Email Verification in Laravel 12 (Step by Step) and Implementing Password Reset in Laravel 12 Without Packages.

Running Tests and Filtering by Class/Method

Run the entire test suite, a single class, or even a single method using filters.

# run all tests
php artisan test

# run a specific class
php artisan test --filter=PostCreationTest

# run a specific test method
php artisan test --filter=PostCreationTest::test_authenticated_user_can_create_postCode language: Bash (bash)

Filtering speeds up the feedback loop while you iterate on a failing scenario.

Sample Output from php artisan test

Here’s a typical output when all tests pass. Your numbers will differ based on how many tests/asser­tions you have.

PHPUnit 10.*/Laravel Test Runner

   PASS  Tests\Unit\UserMathTest
  ✓ test_basic_math_addition

   PASS  Tests\Feature\PostCreationTest
  ✓ test_authenticated_user_can_create_post

  Tests:  2 passed
  Assertions: 3
  Time: 0.58sCode language: Bash (bash)

When a test fails, the output highlights the failing assertion, expected vs actual values, and a snippet of the stack trace to help you navigate the source quickly.

Seeding, Factories, and Faster Test Data

Use model factories and seeders to generate realistic test data quickly. This keeps tests readable and reduces duplication across scenarios.

// Example: creating many posts for a listing test
$posts = \App\Models\Post::factory()->count(10)->create();Code language: PHP (php)

Factories keep your tests expressive and focused on behavior. For deeper coverage, see Using Laravel Factories and Seeders for Test Data.

UI-Related Testing Tips

For Blade-driven UIs, test the rendered output and important view data. Focus on what matters (HTTP status, redirected routes, session flashes, and presence of key strings).

public function test_posts_index_renders_titles()
{
    $posts = \App\Models\Post::factory()->count(2)->create([
        'title' => 'Visible In List'
    ]);

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

    $response->assertOk()
        ->assertSee('Visible In List');
}Code language: PHP (php)

This checks that the index page renders properly and contains expected text. For browser-level interactions (clicks, JS), consider How to Use Laravel Dusk for Browser Testing.

Wrapping Up

You learned how to confirm your PHPUnit setup, create unit and feature tests, filter test runs, read outputs, and leverage factories for fast data setup. A disciplined testing habit yields fewer regressions and more confidence when refactoring.

What’s Next

Continue strengthening your test suite with these related guides:

0 Comments

Leave a Comment

Your email address will not be published. Required fields are marked *

Add Comment *

Name *

Email *

Keep Reading...

How to Use Laravel Dusk for Browser Testing
How to Use Laravel Dusk for Browser Testing

End-to-end browser testing ensures that your application works exactly as a user would experience it. Laravel Dusk provides a simple API to…

Using Laravel Factories and Seeders for Test Data
Using Laravel Factories and Seeders for Test Data

Populating reliable test and demo data is essential for development speed, realistic QA, and repeatable CI. In this guide, you’ll learn what…

How to Schedule Jobs in Laravel with Task Scheduling
How to Schedule Jobs in Laravel with Task Scheduling

Laravel’s task scheduling system allows you to automate repetitive jobs such as clearing caches, sending out reports, or syncing data. Instead of…