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.
| Concept | What it protects | Decision rule |
|---|---|---|
| Feature test | Public workflow confidence | Exercise routing, middleware, validation, action, and response together. |
| Expand/contract | Compatible schema rollout | Add and backfill before removing old behavior. |
| Immutable release | Repeatable rollback | Build 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.
- Describe the Laravel release boundary boundary: its inputs, outputs, invariants, and expected failures.
- Implement the smallest happy path behind an explicit contract.
- Add validation and translate low-level failures into language the caller understands.
- Exercise the boundary with realistic data, then inspect output, logs, and resource cleanup.
- Refactor only after behavior is protected by a repeatable check.
Make the boundary visible
Guided code lab
Test the complete publish path
The test communicates identity, request, response, persistence, and queued side effect.
<?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.
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:checkProduction 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
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
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.