Manually instantiated test doubles are broken since PHPUnit 11.2
| Q | A |
|---|---|
| PHPUnit version | 11.2.0 ... dev-main e0aea4c |
| PHP version | 8.4.6 |
| Installation Method | Composer |
Summary
Up to PHPUnit 11.1.* you can easily instantiate mock yourself. Calling methods on such objects was working fine. Since PHPUnit 11.2.0 (still broken in latest phpunit 12.x) this is no longer the case. You can still instantiate such class, but calling methods on it is broken.
Our use case was feed the FQCN of a mock class to Symfony DI container. DI container is then in charge of instantiating objects.
Ref https://github.com/doctrine/DoctrineBundle/pull/2040
Issue6362Test.php
<?php declare(strict_types=1);
namespace PHPUnit\TestFixture\Issue6362;
use PHPUnit\Framework\TestCase;
interface I
{
public function m(): string;
}
final class Issue6362Test extends TestCase
{
public function testOne(): void
{
$class = $this->createStub(I::class)::class;
$o = new $class;
$o->m();
}
}
Actual
PHPUnit Started (PHPUnit 12.4-g59f70b3a79 using PHP 8.4.12 (cli) on Linux)
Test Runner Configured
Event Facade Sealed
Test Suite Loaded (1 test)
Test Runner Started
Test Suite Sorted
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\Issue6362\Issue6362Test, 1 test)
Test Preparation Started (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Prepared (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Stub Created (PHPUnit\TestFixture\Issue6362\I)
Test Errored (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Typed property TestStub_I_7653f44f::$__phpunit_state must not be accessed before initialization
Test Finished (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Suite Finished (PHPUnit\TestFixture\Issue6362\Issue6362Test, 1 test)
Test Runner Execution Finished
Test Runner Finished
PHPUnit Finished (Shell Exit Code: 2)
Expected
PHPUnit Started (PHPUnit 12.4-g59f70b3a79 using PHP 8.4.12 (cli) on Linux)
Test Runner Configured
Event Facade Sealed
Test Suite Loaded (1 test)
Test Runner Started
Test Suite Sorted
Test Runner Execution Started (1 test)
Test Suite Started (PHPUnit\TestFixture\Issue6362\Issue6362Test, 1 test)
Test Preparation Started (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Prepared (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Stub Created (PHPUnit\TestFixture\Issue6362\I)
Test Passed (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Considered Risky (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
This test did not perform any assertions
Test Finished (PHPUnit\TestFixture\Issue6362\Issue6362Test::testOne)
Test Suite Finished (PHPUnit\TestFixture\Issue6362\Issue6362Test, 1 test)
Test Runner Execution Finished
Test Runner Finished
PHPUnit Finished (Shell Exit Code: 0)
you can easily instantiate mock yourself
This was never a supported use case, sorry.
That's kinda semantics discussion. It was a use case that was working up to Phpunit 11.2, regardless if it was documented or declared as intended to be supported. I mean, these changes broke this https://github.com/sebastianbergmann/phpunit/pull/5804, surely that wasn't your intention? You just didn't know this could be the side effect. Would you entertain idea of someone fixing it, or are you going to actively block such attempt?
I mean, these changes broke this https://github.com/sebastianbergmann/phpunit/pull/5804, surely that wasn't your intention?
This sentence does not make sense to me: "These changes" and "this https://github.com/sebastianbergmann/phpunit/pull/5804" mean the same thing. These are are the changes that were made in PHPUnit 11.2 to support doubling of readonly classes.
It was a use case that was working up to Phpunit 11.2
A use case that relied on internal implementation details that are not covered by the backward compatibility promise for PHPUnit.
Would you entertain idea of someone fixing it, or are you going to actively block such attempt?
I am not going to actively block such an attempt.
However, all I can promise is that I will review a pull request that restores your use case. I am concerned, though, that the necessary changes will introduce more complexity than I am comfortable with.
You will also need to convince me that your use case is valid and must be supported. Personally, I don't see the point of using a dependency injection container with test doubles as you describe.