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?
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.
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);
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
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
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With