Skip to content

Instantly share code, notes, and snippets.

@thorsten
Created May 27, 2025 16:10
Show Gist options
  • Select an option

  • Save thorsten/df336af33819e889f9868ba9382bb9e5 to your computer and use it in GitHub Desktop.

Select an option

Save thorsten/df336af33819e889f9868ba9382bb9e5 to your computer and use it in GitHub Desktop.

Revisions

  1. thorsten created this gist May 27, 2025.
    92 changes: 92 additions & 0 deletions gistfile1.txt
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,92 @@
    PHPUnit 12 has removed deprecated methods like willReturnCallback() and changed how some mock behaviors are defined. Here’s how to rewrite your PHPUnit 12 test code in a compatible way:


    ✅ Original snippet (pre PHPUnit 12)

    $redis = $this->createMock(RedisClient::class);
    $redis->expects($this->exactly(3))
    ->method('callAsync')
    ->willReturnOnConsecutiveCalls(
    resolve(['{}']),
    $this->returnCallback(function (string $command, string $name, string $json) {
    $this->assertEquals('ZREM', $command);
    return resolve(1);
    }),
    resolve(0)
    );



    ✅ Updated for PHPUnit 12

    Since returnCallback() is removed, you need to use ReturnCallback from PHPUnit’s newer stubbing system:

    use PHPUnit\Framework\MockObject\Stub\ReturnCallback;

    $redis = $this->createMock(RedisClient::class);

    $stub = new ReturnCallback(function () {
    // You can vary return values based on the call count
    static $calls = 0;
    $calls++;

    if ($calls === 1) {
    return resolve(['{}']);
    }

    if ($calls === 2) {
    // You can't use $this directly in a static function,
    // so extract assertions outside or inject via closure
    return resolve(1); // maybe add custom checks elsewhere
    }

    return resolve(0);
    });

    $redis->expects($this->exactly(3))
    ->method('callAsync')
    ->will($stub);



    🔁 Alternative with injected $this

    If you need assertions inside the callback, you can capture $this:

    $self = $this;

    $redis = $this->createMock(RedisClient::class);

    $redis->expects($this->exactly(3))
    ->method('callAsync')
    ->will(new ReturnCallback(function (...$args) use ($self) {
    static $i = 0;
    $i++;

    if ($i === 1) {
    return resolve(['{}']);
    }

    if ($i === 2) {
    [$command, $name, $json] = $args;
    $self->assertEquals('ZREM', $command);
    return resolve(1);
    }

    return resolve(0);
    }));



    ✅ Summary of changes for PHPUnit 12:

    Feature Old New (PHPUnit 10+)
    Callback return $this->returnCallback() new ReturnCallback()
    Consecutive calls willReturnOnConsecutiveCalls() Use logic inside ReturnCallback
    Assertions inside stub Inline Capture $this via closure

    Would you like help refactoring your test to avoid mocks altogether or to test async logic more robustly?