Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In PHPUnit, how do I indicate different with() on successive calls to a mocked method?

I want to call my mocked method twice with different expected arguments. This doesn't work because expects($this->once()) will fail on the second call.

$mock->expects($this->once())      ->method('foo')      ->with('someValue');  $mock->expects($this->once())      ->method('foo')      ->with('anotherValue');  $mock->foo('someValue'); $mock->foo('anotherValue'); 

I have also tried:

$mock->expects($this->exactly(2))      ->method('foo')      ->with('someValue'); 

But how do I add a with() to match the second call?

like image 471
james Avatar asked Apr 29 '11 22:04

james


People also ask

Which method is used to create a mock with PHPUnit?

PHPUnit provides methods that are used to automatically create objects that will replace the original object in our test. createMock($type) and getMockBuilder($type) methods are used to create mock object. The createMock method immediately returns a mock object of the specified type.

What is stub in PHPUnit?

Stub. Stubs are used with query like methods - methods that return things, but it's not important if they're actually called. $stub = $this->createMock(SomeClass::class); $stub->method('getSomething') ->willReturn('foo'); $sut->action($stub);


2 Answers

You need to use at():

$mock->expects($this->at(0))      ->method('foo')      ->with('someValue');  $mock->expects($this->at(1))      ->method('foo')      ->with('anotherValue');  $mock->foo('someValue'); $mock->foo('anotherValue'); 

Note that the indexes passed to at() apply across all method calls to the same mock object. If the second method call was to bar() you would not change the argument to at().

like image 75
David Harkness Avatar answered Sep 21 '22 08:09

David Harkness


Referencing from the answer from a similar question,

Since PHPUnit 4.1 you can use withConsecutive eg.

$mock->expects($this->exactly(2))      ->method('set')      ->withConsecutive(          [$this->equalTo('foo'), $this->greaterThan(0)],          [$this->equalTo('bar'), $this->greaterThan(0)]        ); 

If you want to make it return on consecutive calls:

  $mock->method('set')          ->withConsecutive([$argA1, $argA2], [$argB1], [$argC1, $argC2])          ->willReturnOnConsecutiveCalls($retValueA, $retValueB, $retValueC); 

It's not ideal to use at() if you can avoid it because as their docs claim

The $index parameter for the at() matcher refers to the index, starting at zero, in all method invocations for a given mock object. Exercise caution when using this matcher as it can lead to brittle tests which are too closely tied to specific implementation details.

like image 20
Gunith D Avatar answered Sep 22 '22 08:09

Gunith D