> ## Documentation Index
> Fetch the complete documentation index at: https://kawax.biz/llms.txt
> Use this file to discover all available pages before exploring further.

# Mocking

> How to run tests as isolated units using Laravel's mocking and test double capabilities

## Why use mocks

When writing tests, there are operations you don't actually want to run: sending mail, reading and writing to the cache, calling external APIs, and so on.
Replacing these operations with a "fake that pretends to be the real thing" is called mocking.

The benefits of using mocks include:

* **Fast tests** — Tests finish quickly because external services and heavy operations aren't executed
* **Stable tests** — Tests always produce the same results, unaffected by the state of external services
* **Clear test scope** — You can verify a single class or method in isolation

Laravel provides helpers that let you mock events, jobs, facades, and more out of the box.
Internally it uses [Mockery](https://github.com/mockery/mockery), which you can use without complex setup.

```mermaid theme={null}
graph LR
    A["Test"] --> B["Mock<br>(fake)"]
    A --> C["Production code"]
    B --> D["Not executed<br>(external API, mail, etc.)"]
    C --> B
    style B fill:#f9a,stroke:#c66
    style D fill:#eee,stroke:#aaa
```

## Mocking objects

To mock an object that is injected via the service container, bind the mock instance into the container.
The container will then use the mock instance instead of creating the object.

<CodeGroup>
  ```php Pest theme={null}
  use App\Service;
  use Mockery;
  use Mockery\MockInterface;

  test('something can be mocked', function () {
      $this->instance(
          Service::class,
          Mockery::mock(Service::class, function (MockInterface $mock) {
              $mock->expects('process');
          })
      );
  });
  ```

  ```php PHPUnit theme={null}
  use App\Service;
  use Mockery;
  use Mockery\MockInterface;

  public function test_something_can_be_mocked(): void
  {
      $this->instance(
          Service::class,
          Mockery::mock(Service::class, function (MockInterface $mock) {
              $mock->expects('process');
          })
      );
  }
  ```
</CodeGroup>

### The `mock()` method

Laravel's test case base class provides a `mock()` method that lets you write the same thing more concisely.

```php theme={null}
use App\Service;
use Mockery\MockInterface;

$mock = $this->mock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});
```

### The `partialMock()` method

When you want to mock only some methods of an object, use `partialMock()`.
Methods that aren't mocked are executed as usual.

```php theme={null}
use App\Service;
use Mockery\MockInterface;

$mock = $this->partialMock(Service::class, function (MockInterface $mock) {
    $mock->expects('process');
});
```

### The `spy()` method

Spies are similar to mocks, but interactions are verified after the code has run.
While a mock declares "this method should be called" in advance, a spy checks "was this method called?" afterward.

```php theme={null}
use App\Service;

$spy = $this->spy(Service::class);

// ... run the code under test ...

$spy->shouldHaveReceived('process');
```

```mermaid theme={null}
graph TD
    subgraph "Mock"
        M1["Set expectations up front<br>expects('process')"] --> M2["Run code"] --> M3["Automatic verification"]
    end
    subgraph "Spy"
        S1["Set up the spy"] --> S2["Run code"] --> S3["Verify afterward<br>shouldHaveReceived('process')"]
    end
```

## Mocking facades

Unlike ordinary static method calls, [facades](/en/facades) can be mocked.
They have the same testability as dependency injection while offering a concise syntax.

As an example, consider a controller that uses the cache.

```php theme={null}
<?php

namespace App\Http\Controllers;

use Illuminate\Support\Facades\Cache;

class UserController extends Controller
{
    /**
     * Return a list of all users in the application.
     */
    public function index(): array
    {
        $value = Cache::get('key');

        return [
            // ...
        ];
    }
}
```

To mock the `get` method of the `Cache` facade, use `expects()`.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Support\Facades\Cache;

  test('get index', function () {
      Cache::expects('get')
          ->with('key')
          ->andReturn('value');

      $response = $this->get('/users');

      // ...
  });
  ```

  ```php PHPUnit theme={null}
  <?php

  namespace Tests\Feature;

  use Illuminate\Support\Facades\Cache;
  use Tests\TestCase;

  class UserControllerTest extends TestCase
  {
      public function test_get_index(): void
      {
          Cache::expects('get')
              ->with('key')
              ->andReturn('value');

          $response = $this->get('/users');

          // ...
      }
  }
  ```
</CodeGroup>

<Warning>
  Do not mock the `Request` facade. Instead, pass input to HTTP test methods like `get` and `post`. Similarly, instead of mocking the `Config` facade, call `Config::set()` in your test.
</Warning>

## Facade spies

To watch a facade with a spy, call the `spy()` method on the corresponding facade.
Spies are convenient when you want to verify interactions after the code has run.

<CodeGroup>
  ```php Pest theme={null}
  <?php

  use Illuminate\Support\Facades\Cache;

  test('values are stored in cache', function () {
      Cache::spy();

      $response = $this->get('/');

      $response->assertStatus(200);

      Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
  });
  ```

  ```php PHPUnit theme={null}
  use Illuminate\Support\Facades\Cache;

  public function test_values_are_stored_in_cache(): void
  {
      Cache::spy();

      $response = $this->get('/');

      $response->assertStatus(200);

      Cache::shouldHaveReceived('put')->with('name', 'Taylor', 10);
  }
  ```
</CodeGroup>

## Manipulating time

When testing time-dependent logic, it's helpful to change what `now()` or `Carbon::now()` returns.
Laravel's feature test base class provides helpers for manipulating time.

### `travel()` — move through time

<CodeGroup>
  ```php Pest theme={null}
  test('time can be manipulated', function () {
      // Move into the future
      $this->travel(5)->milliseconds();
      $this->travel(5)->seconds();
      $this->travel(5)->minutes();
      $this->travel(5)->hours();
      $this->travel(5)->days();
      $this->travel(5)->weeks();
      $this->travel(5)->years();

      // Move into the past
      $this->travel(-5)->hours();

      // Move to a specific moment
      $this->travelTo(now()->subHours(6));

      // Return to the current time
      $this->travelBack();
  });
  ```

  ```php PHPUnit theme={null}
  public function test_time_can_be_manipulated(): void
  {
      // Move into the future
      $this->travel(5)->milliseconds();
      $this->travel(5)->seconds();
      $this->travel(5)->minutes();
      $this->travel(5)->hours();
      $this->travel(5)->days();
      $this->travel(5)->weeks();
      $this->travel(5)->years();

      // Move into the past
      $this->travel(-5)->hours();

      // Move to a specific moment
      $this->travelTo(now()->subHours(6));

      // Return to the current time
      $this->travelBack();
  }
  ```
</CodeGroup>

### Time travel with closures

If you pass a closure to a time-travel method, time is frozen at the specified moment while the closure runs, and returns to the original time after it completes.

```php theme={null}
$this->travel(5)->days(function () {
    // Test in the state 5 days in the future
});

$this->travelTo(now()->subDays(10), function () {
    // Test at a specific moment
});
```

### `freezeTime()` — stop time

`freezeTime()` freezes the current time. `freezeSecond()` freezes time at the beginning of the current second.

```php theme={null}
use Illuminate\Support\Carbon;

// Freeze time, run a closure, and resume afterward
$this->freezeTime(function (Carbon $time) {
    // ...
});

// Freeze at the start of the current second and run a closure
$this->freezeSecond(function (Carbon $time) {
    // ...
});
```

### Practical example: locking inactive threads

Time manipulation is helpful for testing features like a forum where posts get locked after a period of inactivity.

<CodeGroup>
  ```php Pest theme={null}
  use App\Models\Thread;

  test('forum threads lock after one week of inactivity', function () {
      $thread = Thread::factory()->create();

      $this->travel(1)->week();

      expect($thread->isLockedByInactivity())->toBeTrue();
  });
  ```

  ```php PHPUnit theme={null}
  use App\Models\Thread;

  public function test_forum_threads_lock_after_one_week_of_inactivity(): void
  {
      $thread = Thread::factory()->create();

      $this->travel(1)->week();

      $this->assertTrue($thread->isLockedByInactivity());
  }
  ```
</CodeGroup>

<Info>
  Time manipulation methods like `travel()` are only available in feature tests (classes that extend `Tests\TestCase`). They are not available on PHPUnit's base `TestCase`.
</Info>

## Method reference

### Mocking

| Method                                 | Description                                                    |
| -------------------------------------- | -------------------------------------------------------------- |
| `$this->mock(Class::class, fn)`        | Create a full mock of a class and register it in the container |
| `$this->partialMock(Class::class, fn)` | Mock only some methods                                         |
| `$this->spy(Class::class)`             | Create a spy and register it in the container                  |
| `$this->instance(Class::class, $mock)` | Register an arbitrary mock instance in the container           |
| `Facade::expects('method')`            | Mock a facade method                                           |
| `Facade::spy()`                        | Watch a facade with a spy                                      |
| `$spy->shouldHaveReceived('method')`   | Assert that a method was called on the spy                     |

### Time manipulation

| Method                     | Description                                         |
| -------------------------- | --------------------------------------------------- |
| `$this->travel(n)->unit()` | Move time by the specified unit                     |
| `$this->travelTo(Carbon)`  | Move to a specific moment                           |
| `$this->travelBack()`      | Return to the current time                          |
| `$this->freezeTime(fn)`    | Freeze time and run a closure                       |
| `$this->freezeSecond(fn)`  | Freeze at the start of the second and run a closure |


## Related topics

- [Upgrading from Laravel 9 to 10](/en/blog/upgrade-9-to-10.md)
- [Laravel Socialite (Social Authentication)](/en/socialite.md)
- [Advanced Testing with Pest](/en/advanced/testing-pest.md)
- [Testing](/en/packages/laravel-bluesky/testing.md)
- [Core — AT Protocol Core Operations](/en/packages/laravel-bluesky/core.md)
