Existing customer? Log in here →
Test-Driven Laravel

A comprehensive step-by-step video course on designing robust Laravel applications with TDD.

Sign up to get four free preview lessons on faking external services with custom test doubles.

Or buy now if you're already convinced!

Most examples make testing look pretty easy.

When I was first learning how to test, every example I could find made it seem fairly straightforward.

"Assert 5+5 equals 10? Sure, piece of cake!"

But as soon as I tried to test a real application, I was paralyzed.

"What's the very first test I'm supposed to write for this brand new app?"

"How do I test that this email gets sent?"

"What about this code that needs to talk to the Stripe API?"

Simple examples are fine for learning the basics, but I wanted to know how to apply this stuff to real products that I was actually building on the job.

I’ve spent the last 5 years figuring out how to build web applications with TDD; piecing things together from every resource I could get my hands on.

Test-Driven Laravel is the course I wish I'd had.

Ever since Adam helped tweak my approach to testing a bit, I really enjoy writing them a lot more.

Taylor Otwell, creator of Laravel

What you'll learn

The biggest objective of this course is to teach you how to TDD something real; not just another cookie-cutter to-do app.

We cover fundamentals like:

  • What test should you write first
  • Organizing your test suite
  • Feature tests vs. unit tests
  • Testing validation rules
  • Testing events and background jobs
  • Working with test databases
  • Speeding up your tests with test doubles

...as well as hard topics, like:

  • Testing code that interacts with third-party services
  • Writing your own test doubles from scratch
  • Testing automated payouts with Stripe Connect
  • Testing the sending of mass emails
  • How to test race conditions
  • Testing file uploads and server side image processing

Test-Driven Laravel teaches you how to design a solid test suite for a real-world, marketable product that you could actually charge money for.

The Course Outline

Together we'll build TicketBeast, a platform for local concert promoters to sell tickets to their events.

Over the course of 166 lessons spanning just under 22 hours of content, we'll implement features like:

  • Purchasing tickets via Stripe Checkout
  • Creating and publishing new concert listings
  • Sending bulk emails to ticket holders
  • Generating unique order confirmation numbers and ticket codes
  • Uploading poster images and optimizing them on the server
  • Inviting new users via the console
  • Allowing promoters to connect their Stripe accounts via OAuth 2.0
  • Splitting payments with Stripe Connect

It’s huge, but it’s the most comprehensive TDD resource I’ve ever seen.

Getting the Ball Rolling

What Do We Build First?

Sketching out Our First Test

Getting to Green

Unit Testing Presentation Logic

Refactoring for Speed

Hiding Unpublished Concerts

Testing Query Scopes

Factory States

Purchasing Concert Tickets

Introducing the Next Feature

Browser Testing vs Endpoint Testing

Outlining the First Purchasing Test

Faking the Payment Gateway

Adding Tickets to Orders

Encapsulating Relationship Logic in the Model

Getting Started with Validation Testing

Reducing Duplication with Custom Assertions

Handling Failed Charges

Preventing Ticket Sales to Unpublished Concerts

Limiting Ticket Sales

Outlining the First Test Case

Adding Tickets to Concerts

Refusing Orders When There Are No More Tickets

Finishing the Feature Test

Cancelling Failed Orders

Refactoring and Redundant Test Coverage

Cleaning Up Our Tests

Returning Order Details

Asserting Against JSON Responses

Returning Order Details

This Design Sucks

A Surgical Refactoring

Persisting the Order Amount

Removing the Need to Cancel Orders

Preparing for Extraction

Extracting a Named Constructor

Precomputing the Order Amount

Uncovering a New Domain Object

You Might Not Need a Mocking Framework

Off to the Races

Uh Oh, a Race Condition!

Requestception

Hooking into Charges

Uh Oh, a Segfault!

Replicating the Failure at the Unit Level

Reserving Individual Tickets

Reserved Means Reserved!

That Guy Stole My Tickets!

Hunting for Stale Code

Cancelling Reservations

Refactoring Mocks to Spies

A Change in Behavior

Deleting Stale Tests

Something Smells in Our Controller

Cleaning up a Loose Variable

Moving the Email to the Reservation

Refactoring "Long Parameter List" Using "Preserve Whole Object"

Green with Feature Envy

Avoiding Service Classes with Method Injection

Test-Driving the Real Stripe Adapter

Generating a Valid Payment Token

Retrieving the Last Charge

Making a Successful Charge

Dealing with Lingering State

Don't Mock What You Don't Own

Using Groups to Skip Integration Tests

Handling Invalid Payment Tokens

The Moment of Truth

Keeping Things Synchronized with Contract Tests

When Interfaces Aren't Enough

Refactoring Towards Duplication

Capturing Charges with Callbacks

Making the Tests Identical

Extracting a Contract Test

Extracting the Failure Case

Upgrading Our Suite to Laravel 5.4

Upgrading to Laravel 5.4

Removing the BrowserKit Dependency

Viewing Order Confirmations

Sketching Out Order Confirmations

Driving out the Endpoint

Asserting Against View Data

Extracting a Finder Method

Making Static Data Real

Deciding What to Test in a View

Decoupling Data from Presentation

Generating Confirmation Numbers

Fixing the Test Suite

Stubbing the Interface

Updating Our Unit Tests

Confirmation Number Characteristics

Testing the Confirmation Number Format

Ensuring Uniqueness

Refactoring to a Facade

Storing the Last Four Card Digits

Promoting Charges to Objects

Leveraging Our Contract Tests

Storing Charge Details with Orders

Deleting More Stale Code

Assigning Ticket Codes

Feature Test and JSON Updates

Claiming Tickets When Creating Orders

Assigning Codes When Claiming Tickets

The Birthday Problem

Integrating Hashids

Dealing with Out of Sync Mocks

Wiring It All Together

Ready to Demo

Emailing Order Confirmations

Using a Fake to Intercept Email

Testing Mailable Contents

Cleanup and Demo

Logging in with Dusk

Testing the Login Endpoint

Should You TDD Simple Templates?

Namespacing Our Test Suite

Getting Started with Laravel Dusk

QA Testing the Login Flow

Adding New Concerts

Preventing Guests from Adding Concerts

Adding a Valid Concert

Validation and Redirects

Converting Empty Strings to Null

Reducing Noise with Form Factories

Connecting Promoters and Concerts

Autopublishing New Concerts

Listing a Promoter's Concerts

Asserting Against View Objects

Avoiding Sort-Sensitive Tests

Refactoring Assertions with Macros

Updating Basic Concert Info

Viewing the Update Form

The First Update Test

Driving Out Basic Concert Updates

Restricting Updates to Unpublished Concerts

Postponing Ticket Creation

Storing the Intended Ticket Quantity

Updating the Other Tests

Refactoring Away Some Test Duplication

Creating Tickets at Time of Publish

Custom Factory Classes

Publishing Concert Drafts

Discovering a New Resource

Creating Published Concerts

Adding Concerts without Publishing

Pushing Logic Out of the View

More Custom Assertion Fun

Building the Sales Dashboard

Calculating Tickets Sold

Making the Progress Bar Work

Total Revenue and a Relationship Bug

Listing Recent Orders

Creating a Custom OrderFactory

Asserting Against Sort Order

Splitting Large Tests

Queuing Mass Attendee Emails

Storing Messages for Attendees

Confirming That a Job Was Dispatched

Unit Testing the Job

Refactoring for Robustness

Mailable Testing Refresher and Demo

Upgrading to Laravel 5.5

Upgrading to Laravel 5.5

Uploading Concert Posters

Faking Uploads and File Systems

Storing Files and Comparing Content

Validating Poster Images

Optional Files and the Null Object Pattern

Optimizing Poster Images

Testing Events

Testing the Event Listener

Resizing the Posted Image

Optimizing the Image Size

Inviting Promoters and Accepting Invitations

Upgrading Laravel and Deleting Some Code

Viewing an Unused Invitation

Viewing Used or Invalid Invitations

Registering with a Valid Invitation

Registering with an Invalid Invitation

Validating Promoter Registration

Testing a Console Command

Sending Promoters an Invitation Email

Test-Driving the Email Contents

Automating Payouts with Stripe Connect

Getting Cozy with Stripe Connect

Authorizing with Stripe

Exchanging Tokens

Unit Testing Middleware

Testing Callbacks with Invokables

Testing That Middleware Is Applied

Updating Factories and a Speed Trick

Total Charges for a Specific Account

Paying Promoters Directly

Splitting Payments with Stripe

It's Alive

This course has had a huge impact on my career. It’s easily worth 10x what I paid for it.

Glenn Kimble

Get Test-Driven Laravel

Learn everything you need to know about TDD in one comprehensive resource.

  • Instant access to the private course area
  • Stream and download all 166 lessons immediately
  • Membership to the private course repository on GitHub
  • Source code to each lesson as individual commits
  • Lifetime updates and access to any new material that’s added to the course
Buying for your team? See team pricing options.

Definitely sign up for Adam’s course. Highly recommended.

Jeffrey Way, creator of Laracasts

Frequently Asked Questions

Can I pay with PayPal?

Sure! To pay with PayPal, purchase the course through Gumroad and choose the "PayPal" option during checkout:

Pay with PayPal via Gumroad

An account will be created for you automatically and you'll receive an access link via email shortly after purchasing.

Can I get an invoice?

Absolutely! Right after purchasing you'll be given a link to generate an invoice with any extra information you need to add for your own accounting purposes.

How do I access and watch the videos?

All of the videos are hosted inside of a custom platform I put together just for this course.

Instead of downloading 10 gigs of content, you just login to the course area with your GitHub account and you’ll have access to everything right away.

Every video is available both to stream and to download. You don’t need to fill up your hard drive if you don’t want to, but you can also download lessons for offline viewing whenever you like!

Can I purchase multiple licenses for my team at a reduced price?

Sure! Here's what I've got for team pricing:

  • 3 Developers – $399
  • 5 Developers – $599
  • 8 Developers – $899
  • 10 Developers – $1049
  • 12 Developers – $1249
  • 15 Developers – $1549
  • 20 Developers – $1999
  • 25 Developers – $2499

Team licenses can be purchased through Gumroad:

Buy a team license via Gumroad

After purchasing, you'll receive an email with unique access links you can distribute to the people on your team.

I have another question!

No problem! Shoot me an email and let’s chat!

About Me

Hey! I'm @adamwathan, author of Refactoring to Collections, host of Full Stack Radio, and creator of Nitpick CI.

I teach everything I know on my blog, through screencasts, and at conferences around the world.

© NothingWorks Inc 2025. All rights reserved.