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.
Installation:
composer require digitalrevolution/phpunit-extensions --dev
Ensure your phpunit.xml includes the package's autoloading.
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();
}
}
For PHPUnit 10+ Compatibility:
Use consecutive() helper for mock expectations:
$mock->method('process')->with(...consecutive([1], [2]));
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);
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();
ClockTestTrait:
$this->sleep(3600); // Advance time by 1 hour
$this->assertSameTime(1234567890); // Assert frozen time
$this->assertSameImage($generatedImage, $expectedImage);
$this->assertSamePdf($generatedPdf, $expectedPdf);
Set PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH to debug visual differences.$this->assertJsonResponse($response, 200, ['data' => 'value']);
$this->assertResponseIsRedirection($response);
$mock->method('log')->withConsecutive(
['info', 'Message 1'],
['error', 'Message 2']
);
PDF/Image Dependencies:
ImageTestTrait/PdfTestTrait require Imagick (with Ghostscript for PDFs).PdfTestTrait can resolve a renderer.php.ini:
extension=imagick.so
Symfony Version Mismatches:
composer.json constraints.Time Freezing:
ClockTestTrait auto-resets time per test. Avoid relying on global time state across tests.Consecutive Mocks:
withConsecutive may fail. Use any() for flexible matching:
$mock->method('handle')->withConsecutive(
['arg1', 'arg2'],
['arg3', any()]
);
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.
Custom Traits:
Extend AbstractControllerTestCase or AbstractConstraintValidatorTestCase to add project-specific assertions.
Environment Variables:
Override defaults (e.g., PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH) via .env.testing:
PHPUNIT_EXTENSIONS_IMAGE_DIFF_OUTPUT_PATH=/tmp/test-diffs
PHPUnit Bootstrapping:
Load the package’s autoloader in phpunit.xml:
<php>
<autoload>
<classmap prefix="DR\PHPUnitExtensions"/>
</autoload>
</php>
How can I help you explore Laravel packages today?