Automated Testing in Laravel

Lesson 42 of 50

84%
1. What Is Automated Testing?

Automated testing means writing code that checks whether your application behaves as expected. Laravel provides testing tools that help developers detect problems before deploying an application.

Why is testing important?

  • Find bugs before users encounter them.
  • Check that application features work correctly.
  • Verify API responses and HTTP status codes.
  • Test validation and authentication rules.
  • Make changes with greater confidence.

Common types of tests:

  • Unit tests: Test a small piece of code in isolation.
  • Feature tests: Test application behavior, such as HTTP requests and database interactions.

Laravel projects commonly use PHPUnit or Pest for automated tests. New projects may include a testing framework configured by default.

2. Understand the Testing Folder Structure

Laravel stores automated tests in the tests directory.

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

Feature directory:

Use feature tests to check application behavior, including routes, controllers, validation, and database operations.

Unit directory:

Use unit tests for small pieces of logic that can be tested independently.

The exact files and configuration can differ depending on the Laravel version and whether your project uses PHPUnit or Pest.

3. Create Your First Test

Use Artisan to create a feature test:

php artisan make:test StudentTest

Laravel creates a test file inside tests/Feature.

Example using PHPUnit:

<?php

namespace Tests\Feature;

use Tests\TestCase;

class StudentTest extends TestCase
{
    public function test_home_page_returns_successful_response(): void
    {
        $response = $this->get('/');

        $response->assertStatus(200);
    }
}

Explanation:

  • $this->get('/') sends a simulated HTTP GET request.
  • assertStatus(200) checks that the response has status code 200.
  • The test fails if the expected condition is not met.

This example assumes your application has a home route that returns a successful response.

4. Run Laravel Tests

Run all tests with:

php artisan test

You can also run tests using PHPUnit directly if it is installed and configured in your project:

vendor/bin/phpunit

To run one test file, use:

php artisan test tests/Feature/StudentTest.php

Typical results:

  • PASS: The test's assertions succeeded.
  • FAIL: An assertion did not match the expected result.
  • ERROR: An unexpected exception or test execution problem occurred.

Read the failure message and stack trace to identify which assertion or operation needs attention.

5. Test a Laravel API Endpoint

Laravel feature tests can simulate HTTP requests to your application's API routes.

Create a test for an endpoint that returns a list of students:

<?php

namespace Tests\Feature;

use Tests\TestCase;

class StudentApiTest extends TestCase
{
    public function test_students_api_returns_successful_response(): void
    {
        $response = $this->getJson('/api/students');

        $response->assertOk();
        $response->assertJsonStructure([
            'data',
        ]);
    }
}

This example assumes your /api/students endpoint returns a JSON response containing a top-level data key.

If your endpoint returns a different JSON structure, update the assertions to match its actual response.

Useful response assertions:

$response->assertOk();
$response->assertCreated();
$response->assertNotFound();
$response->assertUnauthorized();
$response->assertJson(['message' => 'Success']);
6. Test Database Operations

Laravel provides testing helpers for checking database operations. The RefreshDatabase trait is commonly used to prepare a clean database state for tests.

Example test for creating a student:

<?php

namespace Tests\Feature;

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

class StudentCreateTest extends TestCase
{
    use RefreshDatabase;

    public function test_student_can_be_created(): void
    {
        $response = $this->postJson('/api/students', [
            'name' => 'Rahul Kumar',
            'email' => 'rahul@example.com',
            'course' => 'Laravel',
        ]);

        $response->assertCreated();

        $this->assertDatabaseHas('students', [
            'email' => 'rahul@example.com',
            'name' => 'Rahul Kumar',
        ]);
    }
}

This test assumes your API accepts these fields, returns HTTP 201 after creation, and uses the students table.

Configure a dedicated testing database or another safe test database setup before running tests that reset database tables. Never run destructive test migrations against production data.

7. Test Validation Errors

Automated tests can verify that Laravel rejects invalid request data.

Example test:

<?php

namespace Tests\Feature;

use Illuminate\Foundation\Testing\RefreshDatabase;
use Tests\TestCase;

class StudentValidationTest extends TestCase
{
    use RefreshDatabase;

    public function test_student_requires_valid_input(): void
    {
        $response = $this->postJson('/api/students', [
            'name' => '',
            'email' => 'invalid-email',
            'course' => '',
        ]);

        $response->assertUnprocessable();

        $response->assertJsonValidationErrors([
            'name',
            'email',
            'course',
        ]);
    }
}

The test sends invalid data and expects HTTP 422, which is commonly used for JSON validation errors.

The test assumes the API requires all three fields and uses Laravel's standard validation response.

Testing invalid input helps ensure that incomplete or incorrect data does not enter your database.

8. Testing Best Practices
  • Write tests for important application behavior.
  • Use clear test names that describe the expected result.
  • Test successful requests and failure scenarios.
  • Use a dedicated testing database.
  • Keep tests independent of one another.
  • Test validation, authentication, and authorization.
  • Use factories to generate test data when appropriate.
  • Run tests after making significant changes.
  • Never depend on real production services or data during ordinary automated tests.

Important:

A passing test means the tested conditions succeeded. It does not guarantee that every possible application behavior is correct. Write tests that cover the most important risks and business rules.

9. Practice Assignment

Build a small automated test suite for your Student API.

  1. Create a feature test for the student list endpoint.
  2. Test that a single student can be retrieved.
  3. Test creating a student with valid data.
  4. Test that invalid email addresses are rejected.
  5. Test updating a student's course.
  6. Test deleting a student.
  7. Test the response for a missing student ID.
  8. Run all tests using php artisan test.

Bonus Task:

Add authentication to your API and write a test that verifies an unauthenticated user cannot access a protected student endpoint.

Quick Quiz

1. Which command runs Laravel's automated tests?




2. Which trait is commonly used to reset the database during tests?




3. What does a feature test commonly test?