ghostika
ghostika

Reputation: 1503

PHPunit mock - call a function in a returned mock

I'm pretty new to phpunit and mocking, and I want to test a Listener in my symfony2 project, what is a kernel exception listener.

This is the class I want to test:

public function onKernelException(GetResponseForExceptionEvent $event)
{
    $code = $event->getException()->getCode();
    if($code == 403)
    {
        $request = $event->getRequest();
        $session = $request->getSession();
        $session->getFlashBag()->add('notice', 'message');
        $session->set('hardRedirect', $request->getUri());
    }
}

And first I just wanted to test, so nothing happens if the code is 404, this is the test I wrote:

public function testWrongStatusCode()
{
    $exceptionMock = $this->getMock('Exception')
                      ->expects($this->once())
                      ->method('getCode')
                      ->will($this->returnValue('404'));

    $eventMock = $this->getMockBuilder('Symfony\Component\HttpKernel\Event\GetResponseForExceptionEvent')
                      ->disableOriginalConstructor()
                      ->getMock();
    $eventMock->expects($this->once())
              ->method('getException')
              ->will($this->returnValue($exceptionMock));

//here call the listener
}

but PHPunit say, getCode function was never called.

Upvotes: 2

Views: 3352

Answers (3)

jdavidbakr
jdavidbakr

Reputation: 195

This is how I mock the getCode() function. It actually gets called from the ResponseInterface::getStatusCode() function, so that is what you need to mock:

$guzzle->shouldReceive('get')
    ->once()
    ->with(
        $url
    )
    ->andThrows(new ClientException(
        "",
        Mockery::mock(RequestInterface::class),
        Mockery::mock(ResponseInterface::class, [
            'getStatusCode' => 404,
        ]),
    ));

Upvotes: 0

Shakil Ahmed
Shakil Ahmed

Reputation: 1521

You can use mockery library with PHPUnit, which is great tool and makes life easier.

$exceptionMock = \Mockery::mock('GetResponseForExceptionEvent');
$exceptionMock->shouldReceive('getException->getCode')->andReturn('404');

Check out documentation for more... and I hope you will love it.

Upvotes: -1

Cyprian
Cyprian

Reputation: 11374

You can't use "chaining" as you've tried. The reason is that methods getMock and will return different objects. That's why you lose your real mock object. Try this instead:

$exceptionMock = $this->getMock('\Exception');
$exceptionMock->expects($this->once())
    ->method('getCode')
    ->will($this->returnValue('404'));

Edit

Ok. The problem is you cannot mock getCode method because it's final and it's impossible to mock final and private methods with PHPUnit.

My suggestion is: just prepare an exception object you want, and pass it as returned value to event mock:

$exception = new \Exception("", 404);
(...)
$eventMock->expects($this->once())
    ->method('getException')
    ->will($this->returnValue($exception));

Upvotes: 2

Related Questions