phpunit icon indicating copy to clipboard operation
phpunit copied to clipboard

MockObject can be used to test consecutive method calls.

Open biozshock opened this issue 2 years ago • 7 comments

Allow mock object to be used to mock methods with same name, but with different parameters. Addresses #4255 and #4026.

This can be easily ported to 9.6. Just let me know if i need to target 9.6.

biozshock avatar Feb 15 '23 01:02 biozshock

Codecov Report

Merging #5203 (99dd3c2) into main (c90bc5b) will decrease coverage by 0.09%. The diff coverage is 50.98%.

@@             Coverage Diff              @@
##               main    #5203      +/-   ##
============================================
- Coverage     81.28%   81.19%   -0.09%     
- Complexity     5844     5866      +22     
============================================
  Files           629      629              
  Lines         18516    18561      +45     
============================================
+ Hits          15051    15071      +20     
- Misses         3465     3490      +25     
Impacted Files Coverage Δ
src/Framework/MockObject/Rule/AnyParameters.php 25.00% <0.00%> (-8.34%) :arrow_down:
src/Framework/MockObject/Matcher.php 54.09% <27.27%> (-5.91%) :arrow_down:
src/Framework/MockObject/Rule/InvocationOrder.php 69.23% <50.00%> (-8.55%) :arrow_down:
src/Framework/MockObject/Rule/Parameters.php 78.94% <66.66%> (-5.37%) :arrow_down:
.../Framework/MockObject/Builder/InvocationMocker.php 92.70% <90.90%> (-0.24%) :arrow_down:

:mega: We’re building smart automated test selection to slash your CI/CD build times. Learn more

codecov[bot] avatar Feb 15 '23 06:02 codecov[bot]

This can be easily ported to 9.6. Just let me know if i need to target 9.6.

PHPUnit 9 is closed for new functionality, the main target is correct.

sebastianbergmann avatar Feb 15 '23 06:02 sebastianbergmann

@sebastianbergmann What's the plan with this PR? Is it gonna be merged anytime soon? It would greatly help our migration from 9.6 to 10.

X-Coder264 avatar Mar 21 '23 16:03 X-Coder264

I did not have time to review this yet. Please note that by now I am very reluctant when it comes to add new functionality to test doubles.

It would help if you could provide real world use cases for the functionality you propose. Tests for test double functionality are usually not really representative and are not helpful for understanding what the functionality they test should be used and how.

sebastianbergmann avatar Mar 21 '23 16:03 sebastianbergmann

Usually this is used to test consecutive calls to the same object.

For example the call that depends on a condition:

$sender->sendMoney($user, $amount);
if ($user->hasParent()) {
    $sender->sendMoney($user->getParent(), $amount * 0.2);
}

The test double of the $sender have 2 test cases:

  1. testUserHaveNoParent with $sender sends $amount to $user once.
  2. testUserHaveParent with $sender sends $amount to $user once and then sends $amount * 0.2 to user's parent.

Or code that depends on the order:

interface Stack
{
    public function handle(Handler $handler): void
}

class Forward implements Stack
{
   public function handle(Handler $handler): void
   {
       for($i=0;$i<count($this->events);$i++) {
          $handler->handle($this->events[$i]);
       }
   }
}


class Backward implements Stack
class Random implements Stack
class Odd implements Stack
....

The test case for each of the classes will check the order in which the event was handled.

In other words when the double is expected to call same method several times with different arguments and/or returns different value depending on arguments.

For more real world use cases you can search github and find PRs like this: https://github.com/symfony/symfony/pull/49621/files https://github.com/doctrine/orm/pull/10501/files

The current PR provides a way to remove the custom code and do it in the standardized way with PHPUnit MockObject API like it was with deprecated withConsecutive, but addressing mentioned issues in the PR description.

biozshock avatar Mar 22 '23 08:03 biozshock

@biozshock

Can you share how you would implement test cases for the examples that you shared in https://github.com/sebastianbergmann/phpunit/pull/5203#issuecomment-1479101454

  • with the current functionality in phpunit/phpunit and
  • with the functionality you propose in this pull request

?

localheinz avatar Mar 23 '23 09:03 localheinz

@localheinz Sure. Something along these lines:


class ForwardTest
{
  public function testOld(): void
  {
    $handler = $this->createMock(Handler::class);
    $handler->method('handle')
      ->withConsecutive($event1, $event2)
      ->willReturnOnConsecutiveCalls($return1, $return2);

   $forward = new Forward();
   $forward->handle($handle);
  }

  public function testNew(): void
  {
    $handler = $this->createMock(Handler::class);
    $handler->expects(self::once())
      ->method('handle')
      ->with($event1)
      ->willReturn($return1)
      ->andThen(self:once())
      ->method('handle')
      ->with($event2)
      ->willReturn($return2);

   $forward = new Forward();
   $forward->handle($handle);
  }
}

biozshock avatar Mar 29 '23 06:03 biozshock

Hello everyone, Any updates or progress here?

albert361 avatar Sep 13 '23 01:09 albert361

@localheinz Has there maybe been any status update in regards to this PR?

X-Coder264 avatar Nov 02 '23 14:11 X-Coder264

Thank you for your contribution. I appreciate the time you invested in preparing this pull request. However, I have decided not to merge it.

sebastianbergmann avatar Jan 13 '24 13:01 sebastianbergmann

Hello @sebastianbergmann , do you know if there's any plan on the roadmap to include this option for future releases? Thanks in advance!

xserrat avatar Feb 19 '24 09:02 xserrat