k0pernikus
k0pernikus

Reputation: 66817

How to check that method of a mockobject was not called only with a specific parameter?

I have a PHPUnit_Framework_MockObject_MockObject of a Logger.

In a unit test, I do not want a call to the warn method to happen with a specific string parameter doNotCallMeWithThisString.

I have come this far:

public function testThis()
{
    ...

    $logger = $this->getMockLogger();
    $logger->expects($this->exactly(0))->method('warn')->with(
        $this->equalTo('doNotCallMeWithThisString')
    );
    ...
}

Yet this fails because exactly(0) marks any call to the warn method as an error even is the string parameter is somethingEntirelyUnrelated.

How can I tell the mock object that any call to warn is fine unless it is called with that specific string?

Upvotes: 3

Views: 99

Answers (2)

Schleis
Schleis

Reputation: 43800

the exactly() method is for asserting how many times an mocked method will be called. Unless you are using $this->at() for the mocked behavior, you don't specify the arguments for a specific call. exactly(0) says that the number of calls should be 0.

Change your mock to this:

 $logger->expects($this->any()) //Or however many times it should be called
        ->method('warn')
        ->with(
              $this->callback(function($argument) {
                  return $argument !== 'doNotCallMeWithThisString';
              })
         )
 );

This uses a callback to check the argument passed to the mocked method and validates that it isn't equal to your string.

The PHPUnit documentation has the constraint types that you can use to verify the arguments of a mock. At this time, it doesn't have a string not equals type. But using the callback, you can make your own. Your callback just needs to check the argument used and returns true if it is ok and false if it isn't.

Upvotes: 2

helmbert
helmbert

Reputation: 38074

You can use the callback assertion. With this, a callback method provided by you will be invoked for each time the parameter is called:

$logger
    ->expects($this->any())
    ->method('warn')
    ->with($this->callback(function($string) {
        return $string !== 'doNotCallMeWithThisString';
    }));

Some important points about this:

  1. Since you don't actually care how often the method is called (or if it's called at all) as long as it's not called with the bad parameter, you need to use $this->any() as invocation count matcher.
  2. The callback constraint will be invoked for each invocation of the mocked method. It has to return TRUE for the constraint to match.

Upvotes: 1

Related Questions