Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

PHPUnit Mock Exception

I have a class which handles errors, including exceptions. If an exception is caught, I will pass the exception as an argument to my exception/error handler.

try {
    someTrowingFnc();
} catch (\Exception $e) {
    this->error->exception($e);
}

Now I want to unit test this error handler and mock the exception.

I am finding it hard to mock the exception so that I can control the exception message, file and line.

$exceptionMock = $this->getMock('Exception', array(
    'getFile',
    'getLine',
    'getMessage',
    'getTrace'
)); // Tried all mock arguments like disable callOriginalConstructor

$exceptionMock->expects($this->any())
    ->method('getFile')
    ->willReturn('/file/name');

$exceptionMock->expects($this->any())
    ->method('getLine')
    ->willReturn('3069');

$exceptionMock->expects($this->any())
    ->method('getMessage')
    ->willReturn('Error test');

The results of the code below always returns NULL

$file   = $exception->getFile();
$line   = $exception->getLine();
$msg    = $exception->getMessage();

Is there a work-around to mock exceptions or am I just doing something wrong?

like image 705
WitteStier Avatar asked Sep 12 '14 21:09

WitteStier


People also ask

How to mock method in 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?

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

The Exception class methods that return the error details such as getFile() etc are defined/declared as final methods. And this is one limitation of PHPUnit currently in mocking methods that are protected, private, and final.

Limitations
Please note that final, private and static methods cannot be stubbed or mocked. They are ignored by PHPUnit's test double functionality and retain their original behavior.

As seen here: https://phpunit.de/manual/current/en/test-doubles.html

like image 94
antoniovassell Avatar answered Nov 15 '22 11:11

antoniovassell


It's a bit of a hack, but try adding something like this to your TestCase:

/**
 * @param object $object        The object to update
 * @param string $attributeName The attribute to change
 * @param mixed  $value         The value to change it to
 */
protected function setObjectAttribute($object, $attributeName, $value)
{
    $reflection = new \ReflectionObject($object);
    $property = $reflection->getProperty($attributeName);
    $property->setAccessible(true);
    $property->setValue($object, $value);
}

Now you can change the values.

$exception = $this->getMock('Exception');
$this->setObjectAttribute($exception, 'file',    '/file/name');
$this->setObjectAttribute($exception, 'line',    3069);
$this->setObjectAttribute($exception, 'message', 'Error test');

Of course, you haven't really mocked the class, though this can still be useful if you have a more complex custom Exception. Also you won't be able to count how many times the method is called, but since you were using $this->any(), I assume that doesn't matter.

It's also useful when you're testing how an Exception is handled, for example to see if another method (such as a logger) was called with the the exception message as a parameter

like image 34
DanielM Avatar answered Nov 15 '22 12:11

DanielM