eboreum / phpunit-with-consecutive-alternative
Do you miss the old "withConsecutive" method in PHPUnit? This library fixes that problem for you.
Requires
- php: >=8.2
- eboreum/caster: ^2.0
- phpunit/phpunit: ^11.5
Requires (Dev)
- phpstan/phpstan: ^2.1.5
- sebastian/diff: ^6.0
- slevomat/coding-standard: 8.15.0
- squizlabs/php_codesniffer: 3.10.1
README
Do you miss the old "withConsecutive" method in PHPUnit? This library solves that problem for you.
Installation
Via Composer (https://packagist.org/packages/eboreum/phpunit-with-consecutive-alternative):
composer install eboreum/phpunit-with-consecutive-alternative
Via GitHub:
git clone git@github.com:eboreum/phpunit-with-consecutive-alternative.git
Using this library
Within a test method — i.e. a method inside a child of \PHPUnit\Framework\TestCase
— simply do the following:
use Eboreum\PhpunitWithConsecutiveAlternative\MethodCallExpectation; use Eboreum\PhpunitWithConsecutiveAlternative\WillHandleConsecutiveCalls; ... $object = $this->createMock(DateTime::class); $willHandleConsecutiveCalls = new WillHandleConsecutiveCalls(); $willHandleConsecutiveCalls->expectConsecutiveCalls( $object, 'setISODate', new MethodCallExpectation($object, 1999, 42), new MethodCallExpectation($object, 2000, 43, 2), ); ... $this->assertSame($object, $object->setISODate(1999, 42)); $this->assertSame($object, $object->setISODate(2000, 43, 2));
Make it easy for yourself
Make your own (abstract) test case class and simply add a proxy method doing the above.
Example:
use Eboreum\PhpunitWithConsecutiveAlternative\MethodCallExpectation; use Eboreum\PhpunitWithConsecutiveAlternative\WillHandleConsecutiveCalls; use PHPUnit\Framework\MockObject\MockObject; use PHPUnit\Framework\TestCase; abstract class AbstractUnitTestCase extends TestCase { /** * @param non-empty-string $methodName */ final public static function expectConsecutiveCalls( MockObject $object, string $methodName, MethodCallExpectation ...$methodCallExpectations, ): void { (new WillHandleConsecutiveCalls())->expectConsecutiveCalls($object, $methodName, ...$methodCallExpectations); } }
⚠️ Notice: We do not hook into \PHPUnit\Framework\MockObject\Builder\InvocationMocker
and so — contrary to the original withConsecutive
— we place the above method on \PHPUnit\Framework\TestCase
instead.
- In simpler terms: You call a method on
\PHPUnit\Framework\TestCase
, with the mock as an argument, rather than calling a method on the mock itself. - This change is largely because PHPUnit utilizes the "final" keyword a lot on classes and does not support decorators, making extending (an instance of) InvocationMocker nigh-impossible (unless we do evil class-override things).
Why was "withConsecutive" removed?
You can see some of the reasoning and discussion about it here: sebastianbergmann/phpunit#4026
The main reason @sebastianbergmann decided to remove withConsecutive
(and at
, by the way) was with the argument: Don't mock what you don't own. Sadly, the resource he links to in sebastianbergmann/phpunit#4026 — being https://thephp.cc/news/2021/04/do-not-mock-what-you-do-not-own — is now a 404 page. Sebastian is a fantastic person and I and many others greatly appreciate his work over the years. Truly! However, I for one disagree with the "Don't mock what you don't own" sentiment. If something is part of the public API — third-part or not — one should be able to and allowed to mock it. Period.
No convenient alternative has been provided in PHPUnit itself.
A core problem — fixed
A core problem was the disjointed connection between arguments and their corresponding return values, as they would be provided in separate methods, i.e.:
withConsecutive
willReturnOnConsecutiveCalls
orwillReturn
In order to make this connection abundantly clear, the value-object class \Eboreum\PhpunitWithConsecutiveAlternative\MethodCallExpectation
has been implemented. Within it is stored a return value (required) and 0 or more arguments.
Notice: You may indeed use callbacks (i.e. \PHPUnit\Framework\TestCase->callback(...)
) for the arguments instead of the actual values.
License & Disclaimer
See LICENSE
file. Basically: Use this library at your own risk.
Contributing
We prefer that you create a ticket and or a pull request at https://github.com/eboreum/phpunit-with-consecutive-alternative, and have a discussion about a feature or bug here.
Credits
Authors
- Kasper Søfren (kafoso)
E-mail: soefritz@gmail.com
Homepage: https://github.com/kafoso