eboreum/phpunit-with-consecutive-alternative

Do you miss the old "withConsecutive" method in PHPUnit? This library fixes that problem for you.

Package info

gitlab.com/eboreum/phpunit-with-consecutive-alternative

Issues

pkg:composer/eboreum/phpunit-with-consecutive-alternative

Statistics

Installs: 2 826

Dependents: 1

Suggesters: 0

Stars: 0

3.0.0 2026-05-30 11:49 UTC

Requires

Suggests

None

Provides

None

Conflicts

None

Replaces

None

MIT 74b647465035a4a982d69c99f1a2557ea3b3defe

phpunitdevwithconsecutive

This package is auto-updated.

Last update: 2026-05-30 09:58:02 UTC


README

πŸ‘ license
πŸ‘ pipeline status
πŸ‘ coverage report
πŸ‘ PHPStan Level

πŸ‘ eboreum-phpunit-with-consecutive-alternative-logo

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 require --dev eboreum/phpunit-with-consecutive-alternative

Via GitLab:

git clone git@gitlab.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: https://github.com/sebastianbergmann/phpunit/issues/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 https://github.com/sebastianbergmann/phpunit/issues/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 or willReturn

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 an issue and or a merge request at https://gitlab.com/eboreum/phpunit-with-consecutive-alternative, and have a discussion about a feature or bug here.

Branch rules

main = 2.x (not a tag): PHP ^8.5.

Previous branches:

  • 1.x: PHP ^8.2.

Credits

Authors