VOOZH about

URL: https://deepwiki.com/hypervel/support/10.2-facade-mocking

⇱ Facade Mocking | hypervel/support | DeepWiki


Loading...
Menu

Facade Mocking

Purpose and Scope

This document explains the facade mocking capabilities built into the base Facade class, which enables testing code that uses facade static methods without executing the underlying services. The system integrates with the Mockery library to provide spies, mocks, and partial mocks that can be swapped in place of real implementations.

For testing specific subsystems with specialized fake implementations, see Event Testing, HTTP Client Testing, and Queue Testing. For general testing patterns and strategies, see Testing Overview.

Overview

The facade mocking system provides three primary methods for test isolation:

MethodPurposeReturnsUse Case
spy()Records interactions without expectationsMockery spy instanceVerify method calls after execution
shouldReceive()Sets up expectations that must be metMockery expectationDefine required behavior upfront
partialMock()Mocks some methods, keeps others realPartial mock instanceTest with selective method overrides

All three methods use the swap() mechanism to replace the facade's underlying instance with a mock object, stored in the static $resolvedInstance cache.

Sources: src/Facades/Facade.php42-93

Spy Pattern with spy()

The spy() method creates a Mockery spy that records all method calls for later verification without defining expectations upfront. This pattern is useful when you want to test that certain interactions occurred without constraining the implementation.

Creating a Spy


Implementation Details

The spy() method follows this process:

  1. Checks if a mock already exists via isMock() src/Facades/Facade.php44
  2. Retrieves the mockable class using getMockableClass() src/Facades/Facade.php48
  3. Creates a Mockery spy using Mockery::spy() src/Facades/Facade.php50
  4. Swaps the spy into the facade using swap() src/Facades/Facade.php51

If the facade root has already been resolved, getMockableClass() returns get_class($root). Otherwise, it returns null, and Mockery creates an anonymous spy.


Sources: src/Facades/Facade.php42-53 src/Facades/Facade.php119-126 src/Facades/Facade.php131-136

Expectation-Based Mocking with shouldReceive()

The shouldReceive() method sets up expectations on facade method calls before they occur. This follows Mockery's expectation pattern and is useful for strict testing where specific interactions are required.

Defining Expectations


Chaining Expectations

The method returns a Mockery expectation object that supports fluent chaining:


Implementation Flow


Sources: src/Facades/Facade.php72-81 src/Facades/Facade.php86-103

Partial Mocking with partialMock()

The partialMock() method creates a mock that delegates unmocked methods to the real implementation. This allows selective method overrides while maintaining real behavior for other methods.

Using Partial Mocks


Implementation

The partialMock() method src/Facades/Facade.php58-67:

  1. Checks if a mock already exists using isMock()
  2. Reuses existing mock or creates fresh mock via createFreshMockInstance()
  3. Calls makePartial() on the mock to enable pass-through behavior

The difference from shouldReceive() is that partialMock() returns the mock itself rather than an expectation, and it calls makePartial() to enable real method delegation.

Sources: src/Facades/Facade.php58-67

The swap() Method

All mocking methods ultimately use swap() to replace the facade's underlying instance. This method can also be used directly to inject custom implementations.

Manual Swapping


Swap Mechanism

The swap() method src/Facades/Facade.php131-136:

  1. Stores the instance in static::$resolvedInstance[$accessor]
  2. Registers the instance in the container using ApplicationContext::getContainer()->instance()

This ensures both the facade's static cache and the container return the swapped instance.


Sources: src/Facades/Facade.php131-136

Mock Detection

The facade system provides two methods for detecting mocked instances:

isMock()

Checks if the current instance is a Mockery mock:


Implementation src/Facades/Facade.php108-114:

  • Retrieves the accessor name
  • Checks if $resolvedInstance[$name] is an instance of LegacyMockInterface

isFake()

Checks if the current instance is a specialized fake (see Event Testing, Queue Testing):


Implementation src/Facades/Facade.php158-164:

  • Checks if $resolvedInstance[$name] is an instance of the Fake marker interface

Sources: src/Facades/Facade.php108-114 src/Facades/Facade.php158-164

Mockery Integration

The facade mocking system integrates tightly with Mockery, a widely-used PHP mocking framework.

Mockery Classes and Interfaces

ComponentPurpose
MockeryMain Mockery class for creating mocks and spies
LegacyMockInterfaceInterface implemented by all Mockery mocks
Mockery::spy()Creates a spy that records interactions
Mockery::mock()Creates a mock object

The facade system uses LegacyMockInterface to detect if an instance is a Mockery mock src/Facades/Facade.php12 src/Facades/Facade.php113

Protected Method Mocking

When creating fresh mocks, the facade system automatically enables protected method mocking:


This allows tests to mock protected methods on the underlying service, which can be useful for testing internal behavior src/Facades/Facade.php91

Sources: src/Facades/Facade.php11-12 src/Facades/Facade.php91 src/Facades/Facade.php113

Testing Workflow

Complete Test Example


Comparison Table

ScenarioMethod to UseReason
Verify method was called with specific argsspy()Records calls for later assertion
Ensure method is called exactly N timesshouldReceive()->times(N)Strict expectation enforcement
Return specific value from facade callshouldReceive()->andReturn()Control return values
Throw exception from facade callshouldReceive()->andThrow()Test error handling
Mock one method, keep others realpartialMock()Selective override
Inject custom implementationswap()Complete control over implementation

Sources: src/Facades/Facade.php42-136

Internal Implementation Details

Resolution Cache

The $resolvedInstance static array src/Facades/Facade.php20 caches resolved instances per facade accessor. When a mock is swapped in, it replaces the cached instance, ensuring all subsequent facade calls use the mock.

getMockableClass() Behavior

The getMockableClass() method src/Facades/Facade.php119-126 determines what class to mock:

  1. Calls getFacadeRoot() to resolve the real instance
  2. If resolved, returns get_class($root)
  3. If not resolved, returns null, causing Mockery to create an anonymous mock

createFreshMockInstance() Flow

The createFreshMockInstance() method src/Facades/Facade.php86-93:


Uses tap() helper to both swap the mock and enable protected method mocking before returning the mock instance.

Sources: src/Facades/Facade.php20 src/Facades/Facade.php86-126

Clearing Mocks

After tests complete, clear mocked instances to prevent test pollution:


The clearResolvedInstance() method src/Facades/Facade.php198-200 removes a specific entry from the cache, while clearResolvedInstances() src/Facades/Facade.php205-207 empties the entire $resolvedInstance array.

Most test frameworks handle this automatically in tearDown methods.

Sources: src/Facades/Facade.php198-207