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

Phony Phpunit Laravel Package

eloquent/phony-phpunit

Integration of the Phony mocking/stubbing library with PHPUnit, providing helpers to use Phony in your test suite. Note: this package is no longer maintained; see the linked statement and consider alternatives or the main Phony repo.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Steps

  1. Installation:

    composer require --dev eloquent/phony-phpunit
    

    Ensure your phpunit.xml or phpunit.php config includes the autoloader.

  2. First Use Case: Replace a PHPUnit mock with a Phony stub in a test:

    use Eloquent\Phony\Phony;
    
    // Traditional PHPUnit
    $mock = $this->createMock(SomeService::class);
    $mock->method('fetchData')->willReturn([]);
    
    // Phony alternative
    $mock = Phony::mock(SomeService::class);
    $mock->when('fetchData')->thenReturn([]);
    
  3. Key Entry Points:

    • Phony::mock(): Create mock objects.
    • Phony::stub(): Create stubs for predictable return values.
    • Phony::spy(): Spy on real objects without mocking.
    • Facade methods like anInstanceOf(), emptyValue().

Where to Look First


Implementation Patterns

Core Workflows

1. Mocking Dependencies

Pattern: Replace external services (e.g., APIs, databases) with mocks.

$mock = Phony::mock(ApiClient::class);
$mock->when('getUser', ['id' => 1])->thenReturn(['name' => 'John']);
$service = new UserService($mock);
$this->assertEquals('John', $service->getUserName(1));

Laravel Example:

$mock = Phony::mock(UsersRepository::class);
$mock->when('find', [1])->thenReturn(new User());
$this->app->instance(UsersRepository::class, $mock);

2. Stubbing Predictable Returns

Pattern: Use stubs for methods with fixed return values (e.g., config, constants).

$stub = Phony::stub(Logger::class);
$stub->when('log')->thenReturn(true);

3. Spies for Verification

Pattern: Spy on real objects to verify interactions (e.g., event dispatchers).

$spy = Phony::spy(new EventDispatcher());
$spy->shouldReceive('dispatch')->with('event.name');

4. Type-Safe Mocks

Pattern: Leverage Phony’s type hints for safer mocks.

$mock = Phony::mock(Collection::class);
$mock->when('first')->thenReturn(anInstanceOf(Model::class));

Integration Tips

Laravel-Specific

  • Service Container: Bind mocks to the container for dependency injection:

    $this->app->bind(UsersRepository::class, function () {
        return Phony::mock(UsersRepository::class)
            ->when('find', [1])->thenReturn(new User());
    });
    
  • Eloquent Models: Stub model queries to avoid database hits:

    $stub = Phony::stub(User::class);
    $stub->when('find', [1])->thenReturn(new User(['name' => 'Test']));
    

Testing Patterns

  • Partial Mocks: Mock only specific methods of a class:

    $partialMock = Phony::partialMock(Service::class);
    $partialMock->when('methodToMock')->thenThrow(new Exception());
    
  • Exception Testing:

    $mock = Phony::mock(Service::class);
    $mock->when('fail')->thenThrow(new RuntimeException('Error'));
    $this->expectException(RuntimeException::class);
    $mock->fail();
    
  • Callback-Based Responses:

    $mock = Phony::mock(Calculator::class);
    $mock->when('add')->then(function ($a, $b) {
        return $a + $b + 1; // Dynamic logic
    });
    

Test Setup/Teardown

  • Trait for Reusable Mocks:

    trait MocksUsersRepository {
        protected function mockUsersRepository(): UsersRepository {
            return Phony::mock(UsersRepository::class)
                ->when('find', [1])->thenReturn(new User())
                ->when('all')->thenReturn(collect());
        }
    }
    
  • Data Providers: Combine with PHPUnit’s data providers for parameterized tests:

    public function testAddWithDataProvider() {
        $mock = Phony::mock(Calculator::class);
        $mock->when('add')->then(function ($a, $b) { return $a + $b; });
    
        $this->assertEquals(5, $mock->add(2, 3));
    }
    

Gotchas and Tips

Pitfalls

  1. Archived Status:

    • No updates for PHPUnit 10+ or Laravel 11+. Plan to migrate if using newer stacks.
    • Workaround: Fork the package or use Phony directly with PHPUnit 9.x.
  2. PHPUnit 9.x Only:

    • Fails with PHPUnit 8.x or earlier. Update your phpunit.xml:
      <phpunit bootstrap="vendor/autoload.php">
          <php>
              <ini name="error_reporting" value="-1" />
          </php>
      </phpunit>
      
  3. Strict Typing Issues:

    • Phony may struggle with final classes or abstract methods. Use emptyValue() as a fallback:
      $mock->when('getFinalClassInstance')->thenReturn(emptyValue());
      
  4. Self-Referential Stubs:

    • Stubs created outside mocks now return self by default (breaking change in v3.0.0). Adjust expectations:
      // Old (may fail):
      $stub = Phony::stub(Service::class);
      $stub->when('getSelf')->thenReturn($stub);
      
      // New (explicit):
      $stub = Phony::stub(Service::class);
      $stub->when('getSelf')->thenReturn($stub->getSelf());
      
  5. Coverage Tools:

    • Mocks/stubs may interfere with coverage tools (e.g., Xdebug). Exclude test directories or use --coverage-filter:
      phpunit --coverage-filter tests/
      

Debugging Tips

  1. Verify Mock Interactions:

    • Use shouldReceive() to enforce method calls:
      $mock->shouldReceive('criticalMethod')->once();
      
  2. Inspect Stubbed Values:

    • Log return values during debugging:
      $mock->when('getData')->then(function () {
          return ['debug' => 'value'];
      });
      
  3. Clear Mocks Between Tests:

    • Phony mocks persist across tests. Reset them in tearDown():
      protected function tearDown(): void {
          Phony::reset();
          parent::tearDown();
      }
      
  4. Type Hinting Errors:

    • If Phony fails to generate a default return value, explicitly define it:
      $mock->when('getUser')->thenReturn(new User()); // Avoid emptyValue()
      

Extension Points

  1. Custom Matchers:

    • Extend Phony’s matchers for complex logic:
      Phony::matcher('isEven', function ($value) {
          return $value % 2 === 0;
      });
      $mock->when('check', isEven())->thenReturn(true);
      
  2. Global Mocks:

    • Override global stubs/mocks in setUp():
      protected function setUp(): void {
          Phony::stub(Logger::class)->when('log')->thenReturn(false);
          parent::setUp();
      }
      
  3. Integration with Laravel Factories:

    • Combine with Laravel’s factories for realistic test data:
      $mock = Phony::mock(User::class);
      $mock->when('find', [1])->thenReturn(User::factory()->create());
      
  4. Hybrid Mocks:

    • Mix Phony with PHPUnit’s assertions:
      $mock = Phony::mock(Service::class);
      $this->assertInstanceOf(Model::class, $mock->getModel());
      

Configuration Quirks

  1. Autoloading:
    • Ensure eloquent/phony-phpunit is listed under require-dev in composer.json:
      "require-dev
      
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.
cadot.eu/make
besmartand-pro/php-quality-config
sentix/ai-chatbot
codifyo/ts-generator-bundle
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