Weave Code
Code Weaver
Helps Laravel developers discover, compare, and choose open-source packages. See popularity, security, maintainers, and scores at a glance to make better decisions.
Feedback
Share your thoughts, report bugs, or suggest improvements.
Subject
Message

Mockery Callable Mock Laravel Package

tmarsteel/mockery-callable-mock

Create Mockery-friendly callable/function mocks in PHP. Set expectations (with args, counts), return values, stubs, and verify calls or non-calls. Can also wrap a real callable to spy while still invoking it. Requires PHP 7+.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation

    composer require --dev tmarsteel/mockery-callable-mock
    

    Add to composer.json under require-dev to avoid production bloat.

  2. First Use Case: Mocking Closures

    use Mockery\MockInterface;
    use Tmarsteel\MockeryCallableMock\CallableMock;
    
    $mock = CallableMock::mock(function() { return 'original'; });
    $mock->shouldReceive('__invoke')
         ->once()
         ->with('test')
         ->andReturn('mocked');
    
    // Usage
    $result = $mock('test'); // Returns 'mocked'
    
  3. First Use Case: Spying on Closures (New in v2.1.0)

    $spy = CallableMock::spy(function() { return 'original'; });
    $spy('test'); // Returns 'original' but records the call
    
    // Verify invocation
    $spy->mockery->mockery_getNumberOfInvocations(); // Returns 1
    
  4. Where to Look First

    • Source Code (if available)
    • CallableMock class for core functionality (including new spy() method)
    • Mockery’s documentation for basic mocking patterns

Implementation Patterns

Workflows

  1. Mocking Anonymous Functions

    $callback = function($x) { return $x * 2; };
    $mock = CallableMock::mock($callback)
        ->shouldReceive('__invoke')
        ->with(5)
        ->andReturn(10);
    
    $result = $mock(5); // Returns 10
    
  2. Spying on Closures (New in v2.1.0)

    $spy = CallableMock::spy(function($x) { return $x * 2; });
    $result = $spy(5); // Returns 10 (original behavior)
    $spy->mockery->mockery_getLastInvocationArgs(); // Returns [5]
    
  3. Integration with Laravel

    • Useful in Service Providers or Test Cases to mock/spy on closures passed via dependency injection.
    • Example in a ServiceProvider:
      $this->app->bind(function ($app) {
          $spy = CallableMock::spy(fn() => 'default');
          return $spy;
      });
      
  4. Partial Mocking

    $mock = CallableMock::mock($originalClosure)
        ->shouldReceive('__invoke')
        ->withArgs(function ($arg) {
            return str_contains($arg, 'test');
        })
        ->andReturn('partial');
    

Tips for Daily Use

  • Leverage Mockery’s Matchers: Combine with Mockery::onConsecutiveCalls() or Mockery::with() for complex scenarios.
  • Type Safety: Ensure closures are type-hinted for better IDE support (e.g., Closure(string): int).
  • Laravel Testing: Pair with PHPUnit for seamless test doubles in HttpTests, FeatureTests, or UnitTests.
  • Spy vs Mock:
    • Use spy when you want to track calls without altering behavior.
    • Use mock when you need to control return values or enforce call constraints.

Gotchas and Tips

Pitfalls

  1. No Modern Mockery Support

    • Last updated in 2017; may conflict with newer Mockery versions (^1.4).
    • Fix: Pin Mockery to ~1.3 in composer.json or fork the package.
  2. Limited Documentation

    • Assumes familiarity with Mockery’s syntax. Refer to Mockery’s docs for edge cases.
  3. Closure Scope Issues

    • Mocked/spied closures lose their original scope (e.g., $this references break).
    • Workaround: Use Closure::bind() or static methods.
  4. Spy Behavior Clarity (New in v2.1.0)

    • Spies do not alter return values by default. If you need to modify behavior, chain shouldReceive() after spying.
    • Example:
      $spy = CallableMock::spy(fn() => 'original')
          ->shouldReceive('__invoke')
          ->with('override')
          ->andReturn('modified');
      

Debugging

  • Verify Mocks/Spies:
    if (!$mock->mockery->mockery_getNumberOfInvocations()) {
        throw new \RuntimeException('Mock/spy was never called!');
    }
    
  • Check Arguments:
    $mock->mockery->mockery_getLastInvocationArgs();
    
  • Assert Spy Calls:
    $spy->mockery->mockery_shouldHaveReceived('__invoke', Mockery::times(1));
    

Extension Points

  1. Custom Matchers Extend CallableMock to add domain-specific argument validation:

    class CustomCallableMock extends CallableMock {
        public function withValidEmail() {
            return $this->with(function ($arg) {
                return filter_var($arg, FILTER_VALIDATE_EMAIL);
            });
        }
    }
    
  2. Laravel Facade Create a helper facade for convenience:

    // app/Providers/AppServiceProvider.php
    Mockery::alias('mockCallable', \Tmarsteel\MockeryCallableMock\CallableMock::class);
    

    Usage:

    $mock = Mockery::mockCallable($closure)->shouldReceive('__invoke')...
    $spy = Mockery::mockCallable($closure)->spy();
    
  3. Performance

    • Avoid over-spying/mocking closures in performance-critical paths (e.g., loops). Prefer real implementations where possible.
    • Spies have minimal overhead but still add slight runtime cost compared to direct calls.
  4. Hybrid Mock-Spy Patterns (New in v2.1.0) Combine spying and mocking for complex scenarios:

    $hybrid = CallableMock::spy(fn() => 'default')
        ->shouldReceive('__invoke')
        ->with('special')
        ->andReturn('handled');
    
    • Calls with 'special' return 'handled'.
    • All other calls return 'default' and are tracked.
Weaver

How can I help you explore Laravel packages today?

Conversation history is not saved when not logged in.
Prompt
Add packages to context
No packages found.
andydefer/laravel-cluster
testo/fiber
mintobit/jobqueue
a4sex/maintenance-bundle
a4sex/entity-date-update
a4sex/client-identifier
a4sex/base-utilites
a4sex/key-value-storage
a4sex/micro-status
chilldev/dependency-injection-extra
datinglibre/datinglibre-app-api
biberltd/corebundle
bricre/symfony-bundle-test
biberltd/logbundle
dominium/http-adapter-bundle
dominium/google-analytics
a4sex/auto-clean-entity
christhompsontldr/laravel-inky
spatie/mailcoach-vapor
spatie/laravel-javascript-views