yvoyer
yvoyer

Reputation: 7516

PHPunit: How to mock a method that has a parameter AND a returned value

Using PHPUnit, I wonder if we can mock an object to test if a method is called with an expected parameter, and a returned value?

In the doc, there are examples with passing parameter, or returned value, but not both...

I tried using this:

// My object to test
$hoard = new Hoard();
// Mock objects used as parameters
$item = $this->getMock('Item');
$user = $this->getMock('User', array('removeItem'));
...
$user->expects($this->once())
     ->method('removeItem')
     ->with($this->equalTo($item));
$this->assertTrue($hoard->removeItemFromUser($item, $user));

My assertion fails because Hoard::removeItemFromUser() should return the returned value of User::removeItem(), which is true.

$user->expects($this->once())
     ->method('removeItem')
     ->with($this->equalTo($item), $this->returnValue(true));
$this->assertTrue($hoard->removeItemFromUser($item, $user));

Also fails with the following message: "Parameter count for invocation User::removeItem(Mock_Item_767aa2db Object (...)) is too low."

$user->expects($this->once())
     ->method('removeItem')
     ->with($this->equalTo($item))
     ->with($this->returnValue(true));
$this->assertTrue($hoard->removeItemFromUser($item, $user));

Also fails with the following message: "PHPUnit_Framework_Exception: Parameter matcher is already defined, cannot redefine"

What should I do to test this method correctly.

Upvotes: 18

Views: 30089

Answers (2)

Vasiliy Toporov
Vasiliy Toporov

Reputation: 875

I know that it's an old post, but it's on the top in searching for PHPUnit warning Method name matcher is already defined, cannot redefine, so I'll answer too.

There is other reason for such warning message. If you describe a mock behaviour in chaining method like this:

$research = $this->createMock(Research::class);
$research->expects($this->any())
    ->method('getId')
    ->willReturn(1)
    ->method('getAgent')
    ->willReturn(1);

You will get warning Method name matcher is already defined, cannot redefine. Just split it in separate statements and the warning will go away (tested on PHPUnit 7.5 and 8.3).

$research = $this->createMock(Research::class);

$research->expects($this->any())
    ->method('getId')
    ->willReturn(1);

$research->expects($this->any())
    ->method('getAgent')
    ->willReturn(1);

Upvotes: 6

David Harkness
David Harkness

Reputation: 36522

You need to use will instead of with for returnValue and friends.

$user->expects($this->once())
     ->method('removeItem')
     ->with($item)  // equalTo() is the default; save some keystrokes
     ->will($this->returnValue(true));    // <-- will instead of with
$this->assertTrue($hoard->removeItemFromUser($item, $user));

Upvotes: 25

Related Questions