Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How can I test if same method is called with correct parameters with PHPUnit and mock object

Tags:

php

phpunit

I am using PHPUnit for my unit tests I am using a mock object to test if a method is called with the correct parameters. This works fine when I just want to do this once.

    $logMock = $this->getMockBuilder('Logger')
            ->disableOriginalConstructor()
            ->getMock();

    //check if it updates the correct record
    $logMock->expects($this->exactly(1))
            ->method('updateLog')
            ->with(456, 'some status');

Now I have the situation that I want to test if the updateLog is called a second time (with different parameters). I don't see how I can do this with the 'with' method.

Does anybody have a suggestion?

like image 729
Fino Avatar asked Nov 21 '10 15:11

Fino


4 Answers

I don't know your mocking framework. Usually you just create another expectation though. I assume that should work with this framework as well.

$logMock->expects($this->exactly(1))
         ->method('updateLog')
         ->with(100, 'something else');

Edit

It seems that the PHPUnit framework doesn't support multiple different expectations on the same method. According to this site you have to use the index functionality.

It would then look like this

$logMock->expects($this->at(0))
        ->method('updateLog')
        ->with(456, 'some status');
$logMock->expects($this->at(1))
         ->method('updateLog')
         ->with(100, 'something else');
$logMock->expects($this->exactly(2))
        ->method('updateLog');
like image 126
treze Avatar answered Oct 06 '22 03:10

treze


returnCallback

If you can't use withConsecutive(), possibly because you are on an old version of PHPUnit, you have another option with returnCallback.

The returnCallback function is invoked each time your mock method is invoked. This means you can save the arguments that are passed to it for later inspection. For instance:

$actualArgs = array();

$mockDependency->expects($this->any())
    ->method('setOption')
    ->will($this->returnCallback(
        function($option, $value) use (&$actualArgs){
            $actualArgs[] = array($option, $value);
        }
    ));

$serviceUnderTest->executeMethodUnderTest();

$this->assertEquals(
    array(
        array('first arg of first call', 'second arg of first call'),
        array('first arg of second call', 'second arg of second call'),
    ),
    $actualArgs);
like image 28
Seth Flowers Avatar answered Oct 06 '22 04:10

Seth Flowers


As of PHPUnit 4.2, you can use the withConsecutive assertion. Provided that you know the order of the calls. Your mock would look like this:

$logMock->expects($this->exactly(2))
        ->method('updateLog')
        ->withConsecutive(
            array(456, 'some status')
            array(100, 'something else')
        );
like image 36
Schleis Avatar answered Oct 06 '22 03:10

Schleis


The previous answer is correct.

you can find the answer in the PHPUnit manual http://www.phpunit.de/manual/3.6/en/phpunit-book.html#test-doubles.mock-objects.tables.matchers search for matchers. Matchers are the classes returned by the functions any(), never() etc... The one you need is the PHPUnit_Framework_MockObject_Matcher_InvokedAtIndex, returned by the method at()

you can find more by browsing PHPUnit classes (add to the project path and use an IDE like netbeans to jump to them and see what you can use)

like image 35
E Ciotti Avatar answered Oct 06 '22 05:10

E Ciotti