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 17 of the Intermediate Laravel: Real-World Application Patterns course
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.

LaravelTestingPHPUnitMockeryDependency InjectionUnit Testingphpbackend

Previously in this course, we discussed Feature Testing Fundamentals, where we wrote end-to-end tests that hit the database. While those are vital for verifying the entire stack, they can become slow and fragile. Today, we're adding mocking to our toolkit, allowing us to isolate controllers from their dependencies, simulate edge cases, and speed up our test suite.

The Problem with Real Dependencies

When you test a controller, you often trigger a chain reaction: the controller calls a service, the service calls a repository, and the repository hits the database. If your test fails, it might be because of a database constraint, a missing record, or a bug in the service layer—not the controller itself.

By leveraging dependency injection, we can swap these real implementations for "mocks" or "stubs" during testing. This allows us to verify that a controller correctly handles a 200 OK or a 500 Internal Server Error without actually executing the underlying business logic.

Mocking Repositories in Controllers

Imagine a TaskController that uses a TaskRepositoryInterface to fetch data. We want to test that the controller returns a JSON response when a task is found, without needing to seed the database.

In Laravel, we use the instance() or mock() methods on the service container to override bindings during a test.

PHP
public function test_can_show_task_details()
{
    #6A9955">// Create a mock of the repository
    $mock = Mockery::mock(TaskRepositoryInterface::class);
    
    #6A9955">// Define the expected behavior
    $mock->shouldReceive('find')
         ->once()
         ->with(123)
         ->andReturn(new Task(['title' => 'Test Task']));

    #6A9955">// Swap the binding in the container
    $this->instance(TaskRepositoryInterface::class, $mock);

    #6A9955">// Call the endpoint
    $response = $this->getJson('/api/tasks/123');

    #6A9955">// Assert the response
    $response->assertStatus(200)
             ->assertJsonPath('data.title', 'Test Task');
}

Simulating Service Failures

One of the biggest benefits of mocking is the ability to trigger "impossible" scenarios, like a database connection timeout or a service-level exception, to see how your app handles them.

If your service throws a custom exception, you don't want to manually break your database to test the error handling. Instead, you instruct your mock to throw the exception.

PHP
public function test_handles_service_failure_gracefully()
{
    $mock = Mockery::mock(TaskService::class);
    
    #6A9955">// Simulate a service failure
    $mock->shouldReceive('createTask')
         ->once()
         ->andThrow(new \Exception('Service unavailable'));

    $this->instance(TaskService::class, $mock);

    $response = $this->postJson('/api/tasks', ['title' => 'New Task']);

    #6A9955">// Assert that we get a 500 or a specific error response
    $response->assertStatus(500);
}

Hands-on Exercise

  1. Open your existing TaskController from Service-Oriented Task Management.
  2. Create a new test file: tests/Feature/TaskControllerTest.php.
  3. Write a test that mocks your TaskService to return an empty array when listTasks() is called.
  4. Assert that the controller returns a 200 OK with an empty data collection.

Common Pitfalls

  • Over-mocking: Don't mock everything. If you mock the repository, the service, and the controller, you're testing your own mocks, not your code. Use mocks for boundaries (external APIs, heavy logic, or complex DB operations).
  • Interface Mismatch: If you rename a method in your Repository Interface but forget to update the mock expectations, your tests will pass (or fail) silently. Always mock against the interface, not the concrete class.
  • Forgetting to Reset: Laravel automatically resets the container between tests, but if you're using Mockery::close() manually, ensure it's in the tearDown method to prevent memory leaks.

Recap

Mocking is a powerful way to isolate components and test edge cases that are difficult to trigger with real data. By injecting interfaces and swapping them with mocks during tests, you ensure your controllers handle success and failure scenarios predictably. This approach complements your broader Repository Pattern implementation, creating a robust, testable architecture.

Up next: We'll look at how to verify side effects like background emails and notifications using Event::fake() and Queue::fake().

Previous lessonFeature Testing FundamentalsNext lesson Testing Events and Jobs
Back to Blog

Similar Posts

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.

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 17 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