Weave 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

digitalrevolution/phpunit-extensions

PHPUnit extensions offering utility classes for easier unit testing: a withConsecutive replacement for PHPUnit 10 migration, plus Symfony AbstractControllerTestCase and ConstraintValidator test case helpers for mocking users, forms, violations, and more.

View on GitHub
Deep Wiki
Context7

Getting Started

Minimal Setup

  1. Installation:

    composer require digitalrevolution/phpunit-extensions --dev
    

    Ensure your phpunit.xml includes the package's autoloading.

  2. First Use Case: For Symfony Controller Testing, extend AbstractControllerTestCase:

    use DR\PHPUnitExtensions\Symfony\AbstractControllerTestCase;
    
    class MyControllerTest extends AbstractControllerTestCase
    {
        public function testAccessDenied()
        {
            $this->expectDenyAccessUnlessGranted('ROLE_ADMIN');
            $this->controller();
        }
    
        protected function getController()
        {
            return new MyController();
        }
    }
    
  3. For PHPUnit 10+ Compatibility: Use consecutive() helper for mock expectations:

    $mock->method('process')->with(...consecutive([1], [2]));
    
  4. PDF Testing (as of v1.14.0): PdfTestTrait now renders and compares PDFs using either TCPDF or TcLibPdf. Pick whichever is already in your stack:

    use DR\PHPUnitExtensions\Pdf\PdfTestTrait;
    
    $this->assertSamePdf($generatedPdf, $expectedPdf);
    

Implementation Patterns

1. Symfony-Specific Testing

  • Controller Tests: Chain assertions before invoking the controller:

    $this->expectGetUser(new User())
         ->expectIsGranted('EDIT', $entity)
         ->expectCreateForm(MyType::class, ['data' => $entity]);
    
  • Validator Tests: Use fluent assertions for violations:

    $this->expectBuildViolation('Invalid value')
         ->expectAtPath('field.name')
         ->expectAddViolation();
    

2. Time Manipulation

  • Freeze time in tests with ClockTestTrait:
    $this->sleep(3600); // Advance time by 1 hour
    $this->assertSameTime(1234567890); // Assert frozen time
    

3. Image/PDF Comparison

  • Compare images or PDFs (requires Imagick; PDFs additionally require TCPDF or TcLibPdf):
    $this->assertSameImage($generatedImage, $expectedImage);
    $this->assertSamePdf($generatedPdf, $expectedPdf);
    
    Set PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH to debug visual differences.

4. Response Assertions

  • Test Symfony responses concisely:
    $this->assertJsonResponse($response, 200, ['data' => 'value']);
    $this->assertResponseIsRedirection($response);
    

5. Mocking Workflows

  • Consecutive Calls:
    $mock->method('log')->withConsecutive(
        ['info', 'Message 1'],
        ['error', 'Message 2']
    );
    

Gotchas and Tips

Pitfalls

  1. PDF/Image Dependencies:

    • ImageTestTrait/PdfTestTrait require Imagick (with Ghostscript for PDFs).
    • PDFs additionally require a PDF renderer: either TCPDF or TcLibPdf (new in v1.14.0). Install exactly one in your dev dependencies so PdfTestTrait can resolve a renderer.
    • Verify extensions are enabled in php.ini:
      extension=imagick.so
      
  2. Symfony Version Mismatches:

    • The package supports Symfony 6–8. Ensure your project’s Symfony version aligns with the package’s composer.json constraints.
  3. Time Freezing:

    • ClockTestTrait auto-resets time per test. Avoid relying on global time state across tests.
  4. Consecutive Mocks:

    • Uneven argument counts in withConsecutive may fail. Use any() for flexible matching:
      $mock->method('handle')->withConsecutive(
          ['arg1', 'arg2'],
          ['arg3', any()]
      );
      

Debugging Tips

  • Image/PDF Diffs: Set PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_URL in CI to point to a public URL for visual debugging:

    export PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_URL="https://ci.example.com/artifacts/diff.html"
    
  • ConstraintValidator Tests: If expectBuildViolation() fails, verify the constraint type matches the validator’s expected input:

    $this->assertHandlesIncorrectConstraintType(MyConstraint::class);
    
  • PDF Renderer Resolution: If PDF comparison fails at setup rather than on the diff, check that a supported renderer (TCPDF or TcLibPdf) is installed and autoloadable. Running both in the same project is unnecessary and may mask which one is being exercised.

Extension Points

  1. Custom Traits: Extend AbstractControllerTestCase or AbstractConstraintValidatorTestCase to add project-specific assertions.

  2. Environment Variables: Override defaults (e.g., PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH) via .env.testing:

    PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH=/tmp/test-diffs
    
  3. PHPUnit Bootstrapping: Load the package’s autoloader in phpunit.xml:

    <php>
        <autoload>
            <classmap prefix="DR\PHPUnitExtensions"/>
        </autoload>
    </php>
    
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.
oxygen/data
oxygen/core
jengo/base
xiloryx/log-collector
a21ns1g4ts/filament-stripe
la-php/laravel-admin
artisan-build/community-prompts
vleroy/smart
ayles-software/laravel-australian-public-holidays
cboxdk/laravel-id-spatie
cboxdk/laravel-id-billing
cboxdk/laravel-id-billing-bridge
simple-as-fuck/php-performance-log
hsluv/hsluv
seampact/codegen
seampact/hooks
seampact/ir
mehedimi/laravel-amp-mail
happones/laravel-vue-i18n-generator
jwerd/inertia-table