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

Phpunit Extensions Laravel Package

lendable/phpunit-extensions

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Install the package:
    composer require --dev lendable/phpunit-extensions
    
  2. Extend the base test case (simplest opt-in):
    use Lendable\PHPUnitExtensions\TestCase;
    
    class MyTest extends TestCase
    {
        public function testExample()
        {
            $mock = $this->createStrictMock(MyClass::class);
            // All methods must be explicitly stubbed; no defaults.
        }
    }
    
  3. Or use the trait (for existing test classes):
    use Lendable\PHPUnitExtensions\StrictMocking;
    
    class MyTest extends \PHPUnit\Framework\TestCase
    {
        use StrictMocking;
    
        public function testExample()
        {
            $mock = $this->createStrictMock(MyClass::class);
            // Strict mocking enforced.
        }
    }
    

First Use Case

Debugging a flaky test: Replace loose mocking:

$mock = $this->createMock(MyClass::class); // Returns defaults (e.g., `0` for `(): int`).

With strict mocking:

$mock = $this->createStrictMock(MyClass::class); // Fails if any method is called unstubbed.

This catches unintended assumptions early.


Implementation Patterns

Core Workflow: Strict Mocking

  1. Opt-in globally via TestCase or per-class via StrictMocking trait.
  2. Explicit stubbing:
    $mock = $this->createStrictMock(MyService::class);
    $mock->expects($this->once())
         ->method('fetchData')
         ->willReturn(['test']);
    
  3. Fail fast: Unstubbed methods throw BadMethodCallException (vs. returning defaults).

Integration with Laravel

  • Service Container Mocks:
    $mock = $this->createStrictMock(MyService::class);
    $this->app->instance(MyService::class, $mock);
    
  • HTTP Tests: Extend LendableTestCase alongside Laravel’s TestCase (if using traits):
    use Lendable\PHPUnitExtensions\StrictMocking;
    
    class FeatureTest extends \Tests\TestCase
    {
        use StrictMocking;
    
        // Strict mocking applies to all test methods.
    }
    

PHPStan Enforcement

  1. Add to phpstan.neon:
    includes:
        - vendor/lendable/phpunit-extensions/phpstan/rules.neon
    
  2. Configure exclusions (temporarily):
    lendable_phpunit:
        enforceStrictMocking:
            pardoned:
                - Tests\Legacy\OldTest
    
  3. Run static analysis:
    vendor/bin/phpstan analyse
    

Partial Mocking

Use createStrictPartialMock for classes with __construct:

$mock = $this->createStrictPartialMock(MyClass::class, ['arg1']);
$mock->method('unstubbedMethod')->willThrowException(new \RuntimeException());

Gotchas and Tips

Pitfalls

  1. Existing Tests Break:

    • Loose mocks (e.g., createMock()) return defaults (e.g., 0 for (): int). Strict mocks fail if unstubbed.
    • Fix: Update tests to explicitly stub all methods or add to pardoned list.
  2. Trait Composition Conflicts:

    • If using Laravel’s RefreshDatabase trait, ensure it doesn’t override createMock:
      // Avoid this in strict tests:
      $mock = $this->getMockBuilder(MyClass::class)->getMock();
      
    • Solution: Stick to createStrictMock()/createStrictPartialMock().
  3. PHPStan False Positives:

    • Dynamic method calls (e.g., $mock->{$method}()) may trigger false positives.
    • Workaround: Use pardoned or suppress rules for specific classes.
  4. Performance Overhead:

    • Strict mocks add minor runtime checks. Benchmark if tests are slow:
      vendor/bin/phpunit --coverage-text
      

Debugging Tips

  • Enable verbose mock errors:
    $this->createStrictMock(MyClass::class, [], '', true); // 4th arg: enable exceptions.
    
  • Check PHPStan output:
    vendor/bin/phpstan analyse --level=max --error-format=github
    
  • Temporarily disable strict mocking for a test:
    $mock = $this->createMock(MyClass::class); // Bypass strict mode.
    

Extension Points

  1. Custom Strict Mock Builder: Extend Lendable\PHPUnitExtensions\StrictMockBuilder for project-specific defaults:

    class ProjectMockBuilder extends StrictMockBuilder
    {
        protected function getDefaultMethods(): array
        {
            return ['__toString' => $this->returnValue('mock')];
        }
    }
    
  2. Rector Rules: Use the bundled EnforceDisableReturnValueGenerationForTestDoublesRector to auto-add #[DisableReturnValueGenerationForTestDoubles] to test classes:

    vendor/bin/rector process src/tests --dry-run
    
  3. Laravel Service Providers: Override createApplication() to enforce strict mocks in HTTP tests:

    protected function createApplication()
    {
        $app = require __DIR__.'/../../bootstrap/app.php';
        $app->make(\Lendable\PHPUnitExtensions\StrictMocking::class);
        return $app;
    }
    

Configuration Quirks

  • PHPUnit 13+ Compatibility: The package requires PHPUnit 12+ (as of v0.4.0). If using Laravel’s default PHPUnit 9.x:
    composer require --dev phpunit/phpunit:^12
    
  • IDE Support: Ensure your IDE (e.g., PHPStorm) has PHPStan integration to catch strict mocking violations early.

Pro Tips

  1. Pair with Mockery: For complex mocks, use Mockery alongside strict PHPUnit mocks:
    $mock = Mockery::mock(MyClass::class)->makeStrict();
    
  2. Test Data Factories: Combine with Laravel’s factories for consistent test data:
    $mock = $this->createStrictMock(User::factory()->make()->toArray());
    
  3. CI/CD Gating: Block PRs with PHPStan violations:
    # .github/workflows/tests.yml
    jobs:
      test:
        runs-on: ubuntu-latest
        steps:
          - run: vendor/bin/phpstan analyse --level=max
    
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.
terminal42/code-quality-tools
codifyo/ts-generator-bundle
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