• Fri, Mar 2026

Testing in Laravel with PHPUnit and Pest: From Unit Tests to Feature Tests

Testing in Laravel with PHPUnit and Pest: From Unit Tests to Feature Tests

This guide will take you deep into testing in Laravel using both PHPUnit and Pest. You will learn step by step how to set up testing, write unit and feature tests, test APIs, and follow test-driven development (TDD) principles. Complete with code examples, actionable instructions, and best practices, this guide is designed to make you professional in testing.

Introduction

Testing is one of the most crucial aspects of modern software development. It ensures that your code works as expected, prevents future bugs, and helps maintain confidence when making changes. Laravel, being a developer-friendly framework, comes with built-in testing support using PHPUnit and also integrates beautifully with Pest, a modern PHP testing framework.

In this article, we’ll cover everything you need to know about testing in Laravel. You’ll learn about PHPUnit, Pest, unit testing, feature testing, database testing, API testing, and test-driven development (TDD). By the end, you’ll be equipped to write effective and maintainable tests for your Laravel applications.

Why Testing Matters in Laravel

Before diving into the practical details, let’s understand why testing is important in Laravel development:

  • Confidence: Tests give you confidence that your code works as intended.
  • Prevent regressions: Automated tests catch bugs before they reach production.
  • Documentation: Tests serve as executable documentation for your code.
  • Refactoring safety: With tests in place, you can refactor code without fear of breaking features.

Laravel encourages testing by providing a rich testing environment out of the box.

Getting Started with Testing in Laravel

Default Testing Setup

Laravel applications come preconfigured with PHPUnit. You’ll find a phpunit.xml file in the root directory and a tests/ directory containing sample tests.


# Run all tests
php artisan test

# Or directly with PHPUnit
vendor/bin/phpunit
    

The php artisan test command is a wrapper around PHPUnit, offering better output formatting.

Test Directory Structure

By default, Laravel’s test directory looks like this:


tests/
├── Feature/
│   └── ExampleTest.php
└── Unit/
    └── ExampleTest.php
    

Feature tests test larger parts of your application (like routes, controllers). Unit tests focus on small, isolated pieces of code.

Unit Testing with PHPUnit

Let’s start with unit testing in Laravel.

Creating a Unit Test


php artisan make:test MathHelperTest --unit
    

This creates tests/Unit/MathHelperTest.php.


namespace Tests\Unit;

use PHPUnit\Framework\TestCase;

class MathHelperTest extends TestCase
{
    public function test_addition()
    {
        $this->assertEquals(4, 2 + 2);
    }
}
    

Run this test:


php artisan test --filter=MathHelperTest
    

Feature Testing with PHPUnit

Creating a Feature Test


php artisan make:test UserTest
    

This creates tests/Feature/UserTest.php. Here’s an example:


namespace Tests\Feature;

use Tests\TestCase;

class UserTest extends TestCase
{
    public function test_users_page_loads()
    {
        $response = $this->get('/users');
        $response->assertStatus(200);
    }
}
    

Testing Database Interactions

Laravel provides traits like RefreshDatabase to reset the database between tests.


namespace Tests\Feature;

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

class UserTest extends TestCase
{
    use RefreshDatabase;

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

        $this->assertDatabaseHas('users', ['email' => $user->email]);
    }
}
    

Working with Factories and Seeders in Tests

Laravel’s model factories make test data creation simple:


$user = User::factory()->create([
    'name' => 'John Doe',
]);
    

Factories ensure tests remain readable and maintainable.

API Testing in Laravel

You can easily test APIs with Laravel’s JSON testing helpers.


public function test_api_returns_users()
{
    $response = $this->getJson('/api/users');
    $response->assertStatus(200)
             ->assertJsonStructure([
                 '*' => ['id', 'name', 'email']
             ]);
}
    

Introduction to Pest

Pest is a testing framework for PHP that focuses on simplicity and elegance. It integrates seamlessly with Laravel and provides a syntax that is more expressive than PHPUnit.

Installing Pest


composer require pestphp/pest --dev
composer require pestphp/pest-plugin-laravel --dev
php artisan pest:install
    

Now you can run Pest tests with:


./vendor/bin/pest
    

Writing Tests with Pest

Here’s a simple Pest test:


test('addition works', function () {
    expect(2 + 2)->toBe(4);
});
    

Feature Test with Pest


it('loads the users page', function () {
    $this->get('/users')
        ->assertStatus(200);
});
    

Database Testing with Pest


it('creates a user', function () {
    $user = \App\Models\User::factory()->create();
    expect($user->exists)->toBeTrue();
});
    

Comparing PHPUnit and Pest

Here’s a quick comparison:

AspectPHPUnitPest
SyntaxVerbose, class-basedMinimal, closure-based
Learning CurveSteeper for beginnersEasier and cleaner
IntegrationBuilt into LaravelRequires installation
Best ForTraditional PHPUnit usersDevelopers who like clean syntax

Test-Driven Development (TDD) with Laravel

TDD involves writing tests before writing actual code.

Step 1: Write a Failing Test


it('returns the correct user name', function () {
    $user = \App\Models\User::factory()->create(['name' => 'Alice']);
    expect($user->name)->toBe('Alice');
});
    

Step 2: Write Code to Pass the Test


// User model already has name property
    

Step 3: Refactor

Clean up code while ensuring tests still pass.

Advanced Testing Techniques

Mocking in Tests

Mock external services to isolate your tests:


$this->mock(ServiceClass::class, function ($mock) {
    $mock->shouldReceive('perform')
         ->once()
         ->andReturn(true);
});
    

Testing Events and Jobs


Event::fake();
User::factory()->create();
Event::assertDispatched(UserRegistered::class);
    

Best Practices for Testing in Laravel

  • Write tests for critical features first.
  • Use descriptive test names.
  • Organize tests into logical groups.
  • Leverage factories for test data.
  • Run tests frequently during development.

Conclusion

Testing in Laravel is powerful and flexible. With PHPUnit’s traditional approach and Pest’s elegant syntax, you can choose the style that best fits your team. Whether you’re testing small units of code, full features, or APIs, Laravel provides tools that make the process smooth and effective.

This website uses cookies to enhance your browsing experience. By continuing to use this site, you consent to the use of cookies. Please review our Privacy Policy for more information on how we handle your data. Cookie Policy