Phase 6 · Laravel MasteryModule 39~62 min read

Testing & Deploying Laravel

Test HTTP and database behavior, use fakes effectively, optimize production builds, and plan zero-downtime releases.

What you'll learn

Prove the Laravel application at the HTTP and database boundaries, then release it as an immutable, observable artifact. Factories and fakes create focused tests; deployment ordering keeps migrations, workers, caches, and rollback compatible.

By the end of this lesson, you'll be able to:

  • Write Laravel feature and database tests
  • Use factories and fakes for clear setup
  • Plan a zero-downtime compatible deployment

Core mental model

Professional PHP is less about memorizing APIs and more about choosing a clear boundary for each responsibility. Use this table as a decision guide while reading the examples.

ConceptWhat it protectsDecision rule
Feature testPublic workflow confidenceExercise routing, middleware, validation, action, and response together.
Expand/contractCompatible schema rolloutAdd and backfill before removing old behavior.
Immutable releaseRepeatable rollbackBuild once and promote the same artifact.

Professional workflow

Build the feature in small, verifiable steps. Each step leaves the system in a state you can test.

  1. Describe the Laravel release boundary boundary: its inputs, outputs, invariants, and expected failures.
  2. Implement the smallest happy path behind an explicit contract.
  3. Add validation and translate low-level failures into language the caller understands.
  4. Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
  5. Refactor only after behavior is protected by a repeatable check.

Make the boundary visible

Name inputs, outputs, side effects, and failure cases before adding framework or infrastructure code. That habit keeps advanced PHP understandable as the application grows.

Guided code lab

Test the complete publish path

The test communicates identity, request, response, persistence, and queued side effect.

PublishCourseTest.php
<?php
use Illuminate\Support\Facades\Queue;

test('an author can publish their course', function (): void {
    Queue::fake();
    $author = User::factory()->create();
    $course = Course::factory()->for($author, 'author')->draft()->create();

    $this->actingAs($author)->post(route('courses.publish', $course))
        ->assertRedirect(route('courses.show', $course));

    $this->assertDatabaseHas('courses', ['id' => $course->id, 'status' => 'published']);
    Queue::assertPushed(NotifyCourseFollowers::class);
});

Run production optimization deliberately

These commands belong in a release step after dependencies are installed and before traffic moves.

release.sh
composer install --no-dev --prefer-dist --no-interaction --optimize-autoloader
php artisan config:cache
php artisan route:cache
php artisan view:cache
php artisan migrate --force
php artisan queue:restart
php artisan health:check

Production practice

Contract

A release declares code artifact, configuration, migration compatibility, worker behavior, health checks, and rollback conditions.

Verification

Run quality gates on the artifact, smoke-test staging, then canary production with automated health and error checks.

Operations

Monitor HTTP and queue signals during rollout; retain the prior artifact and database compatibility until confidence is earned.

Common failure mode

Rolling back code cannot reverse a destructive migration safely after new data is written. Use backward-compatible expand/contract changes.

Independent workshop

Create a tested delivery pipeline for the course platform with staged schema evolution and a worker-safe rollout.

Your finished workshop must include:

  • Feature suite including failed authorization
  • Build/release/run command separation
  • Zero-downtime sequence, health checks, and rollback runbook

Definition of done

Run the happy path and at least two failure paths, explain one design tradeoff in a short README, and leave the code formatted and ready for review.

Recap & quick check

Key takeaways

  • Feature tests prove public workflows.
  • Fakes verify dispatch; handler tests verify work.
  • Build artifacts should be immutable.
  • Schema and worker compatibility drive safe rollout order.

Quick check

1. What does Queue::fake primarily verify?

2. Why use expand/contract migrations?

3. What should queue:restart do during release?

Keep the workshop: later phases deliberately build on these boundaries, so today's small example can become part of your portfolio architecture.