Mahamudul Hasan Rubel
HomeBlogCoursesAboutProjectsSkillsExperiencePhotosContact
Mahamudul Hasan Rubel

Senior Software Engineer crafting high-performance web applications and SaaS platforms.

Navigation

  • Home
  • Blog
  • Courses
  • About
  • Projects
  • Skills
  • Experience
  • Photos
  • Contact

Get in Touch

Available for senior/lead roles and consulting.

bd.mhrubel@gmail.comHire Me

Subscribe to the newsletter

Get new articles and course lessons delivered to your inbox. No spam, unsubscribe anytime.

© 2026 Mahamudul Hasan Rubel. All rights reserved.

Built with using Next.js 16 & Tailwind v4

Back to Blog
Lesson 51 of the Intermediate Laravel: Real-World Application Patterns course
LaravelJune 26, 20263 min read

Testing with Test Doubles: Mastering Mocks and Stubs in Laravel

Stop hitting live APIs in your tests. Learn how to use test doubles, stubs, and mocks to isolate your Laravel application logic for faster, reliable tests.

LaravelTestingPHPUnitMockeryMockingStubsphpbackend

Previously in this course, we explored Advanced Testing: Integration Tests in Laravel, where we covered maintaining database state across complex workflows. While integration tests are essential, they can become slow and fragile when they rely on third-party APIs like Stripe, Twilio, or GitHub.

In this lesson, we move beyond database-centric testing to isolate your business logic entirely using test doubles. By replacing real network-dependent objects with controlled substitutes, you ensure your tests remain deterministic, lightning-fast, and decoupled from the instability of the outside world.

The First Principles of Test Doubles

In testing, a "test double" is a generic term for any object used in place of a real production object. Think of it like a stunt double in a movie: they look and act like the real thing, but they are under your complete control.

We primarily use three types of doubles in Laravel:

  • Stubs: Provide canned answers to calls made during the test. Use these when your code needs data from an external service to proceed.
  • Mocks: Assert that specific methods were called with specific arguments. Use these when you need to verify that your code triggered an action (e.g., "Did I actually send this email?").
  • Fakes: Higher-level abstractions provided by Laravel that handle the heavy lifting for you (e.g., Mail::fake()).

Mocking External Services in Practice

Imagine our project board application needs to fetch a user's GitHub profile to display their avatar. If we hit the GitHub API every time we run our test suite, we risk hitting rate limits or causing intermittent failures due to network latency.

Instead, we mock the service. First, ensure your service is behind an interface, which we touched on in our Repository Pattern Fundamentals lesson.

The Worked Example

Suppose we have a GitHubClientInterface. We want to test that our ProfileService correctly handles the user's data.

PHP
#6A9955">// In your test file
public function test_it_returns_formatted_profile_data()
{
    #6A9955">// 1. Create a mock of the interface
    $mock = Mockery::mock(GitHubClientInterface::class);

    #6A9955">// 2. Define the expectation(The Stub)
    $mock->shouldReceive('getUser')
         ->once()
         ->with('laravel-user')
         ->andReturn(['name' => 'John Doe', 'avatar' => 'https:#6A9955">//path.to/image.jpg']);

    #6A9955">// 3. Bind the mock into the Laravel Container
    $this->app->instance(GitHubClientInterface::class, $mock);

    #6A9955">// 4. Run the code that uses the service
    $service = app(ProfileService::class);
    $result = $service->getProfile('laravel-user');

    #6A9955">// 5. Assert the result
    $this->assertEquals('John Doe', $result['name']);
}

By binding the mock into the container, any class that resolves GitHubClientInterface via dependency injection will receive our "stunt double" instead of the real HTTP client.

Hands-on Exercise

For our running project, implement a test for your TaskAssignmentService.

  1. Identify the external dependency (e.g., a notification service or an external task tracker).
  2. Create a test file using php artisan make:test TaskAssignmentTest.
  3. Use Mockery::mock() to simulate a successful response from that service.
  4. Assert that your service correctly processes the response and updates the Task record in the database.

Common Pitfalls

Even senior engineers fall into these traps when using test doubles:

  • Mocking Implementation Details: Don't mock every single private method. If you find yourself mocking too much, your code is likely too tightly coupled. Test the public interface, not the internal steps.
  • Over-Mocking: If you mock everything, you aren't testing your application; you're testing your ability to configure mocks. Only mock what you cannot control (network, time, random number generators).
  • Forgetting to Reset: If you bind a mock to the container in setUp, ensure you are aware of the scope. Laravel's Mockery integration usually cleans up, but manual instance() bindings might persist if not handled carefully.

Summary

Test doubles are the secret to a stable CI/CD pipeline. By using stubs to provide data and mocks to verify interactions, you decouple your business logic from the unpredictable nature of external infrastructure. This is the foundation for the Mocking Services and Repositories in Laravel Tests pattern, allowing you to build complex features with absolute confidence.

Up next: We'll dive into Testing Events and Jobs, where we'll leverage Laravel's built-in fakes to verify asynchronous workflows without actually firing off background processes.

Previous lessonAPI Documentation with OpenAPINext lesson Implementing Multi-Tenancy
Back to Blog

Similar Posts

LaravelJune 26, 20263 min read

Mocking Services and Repositories in Laravel Tests

Master dependency injection and mocking to isolate your controllers. Learn to simulate failures and test your business logic without hitting the database.

Read more
LaravelJune 28, 20263 min read

Testing DDD Components: Isolating Domain Logic in Laravel

Master Testing DDD components in Laravel. Learn to mock external services, isolate domain logic, and write reliable PHPUnit tests for your Action classes.

Part of the course

Intermediate Laravel: Real-World Application Patterns

intermediate · Lesson 51 of 58

  1. 1

    Architecting for Maintainability

    3 min
  2. 2

    Implementing the Service Layer

    3 min
  3. 3

    Repository Pattern Fundamentals

    3 min
Read more
LaravelJune 26, 20264 min read

Feature Testing Fundamentals: Automating Laravel API Verification

Master feature testing in Laravel. Learn to set up your environment, write tests for API endpoints, and assert JSON responses to build rock-solid applications.

Read more
  • 4

    Project Board Domain Modeling

    3 min
  • 5

    Advanced Eloquent Scopes and Accessors

    4 min
  • 6

    Service-Oriented Task Management

    3 min
  • 7

    REST API Fundamentals with Sanctum

    3 min
  • 8

    Resource Controllers and API Responses

    3 min
  • 9

    Handling API Validation and Form Requests

    3 min
  • 10

    Implementing Middleware for API Security

    4 min
  • 11

    Database Transactions for Data Integrity

    3 min
  • 12

    Error Handling and Global Exceptions

    3 min
  • 13

    Introduction to Laravel Events and Listeners

    3 min
  • 14

    Asynchronous Processing with Queues

    4 min
  • 15

    Job Chaining and Batching

    3 min
  • 16

    Feature Testing Fundamentals

    4 min
  • 17

    Mocking Services and Repositories in Tests

    3 min
  • 18

    Testing Events and Jobs

    3 min
  • 19

    Database Factories and Seeding

    3 min
  • 20

    API Versioning Strategies

    4 min
  • 21

    Advanced Request Filtering and Sorting

    3 min
  • 22

    Handling File Uploads in REST APIs

    3 min
  • 23

    Real-time Notifications with Broadcasting

    3 min
  • 24

    Using Observers for Model Lifecycle Hooks

    3 min
  • 25

    Implementing Policies for Authorization

    3 min
  • 26

    Customizing Authentication Guards

    3 min
  • 27

    Rate Limiting API Endpoints

    4 min
  • 28

    Eloquent Performance Optimization

    4 min
  • 29

    Caching Strategies for Performance

    4 min
  • 30

    Using Traits for Code Reuse

    3 min
  • 31

    Advanced Dependency Injection with Service Providers

    3 min
  • 32

    Command Line Tools with Artisan

    3 min
  • 33

    Scheduled Tasks and Cron Jobs

    3 min
  • 34

    Integrating Third-Party Services

    3 min
  • 35

    Handling Webhooks

    3 min
  • 36

    Logging and Monitoring

    3 min
  • 37

    Database Migrations Best Practices

    3 min
  • 38

    Advanced Testing: Integration Tests

    4 min
  • 39

    Testing API Authentication

    4 min
  • 40

    Code Quality and Static Analysis

    3 min
  • 41

    Project Structure for Large Applications

    3 min
  • 42

    Environment and Configuration Management

    3 min
  • 43

    Deploying Laravel Applications

    4 min
  • 44

    Database Indexing Strategies

    4 min
  • 45

    Using Value Objects

    4 min
  • 46

    Strategy Pattern for Business Rules

    3 min
  • 47

    Advanced Queue Monitoring

    3 min
  • 48

    Building a Search API

    3 min
  • 49

    Handling Concurrency and Race Conditions

    4 min
  • 50

    API Documentation with OpenAPI

    3 min
  • 51

    Testing with Test Doubles

    3 min
  • 52

    Implementing Multi-Tenancy

    4 min
  • 53

    Refactoring Legacy Code

    4 min
  • 54

    Using Middleware for Feature Flags

    3 min
  • 55

    Building Reusable Packages

    4 min
  • 56

    Performance Profiling

    3 min
  • 57

    Secure API Design

    3 min
  • 58

    Event Sourcing Concepts

    4 min
  • View full course