PHPUnit - Throwing, capturing and handling custom exceptions - php

I'm trying to test a capturing and handling a custom exception in PHP.
I've extended the base exception type with some extra properties and methods.
One of the classes I'm stubbing can throw an exception, I want to be able to test that I'm correctly capturing and handling that exception (which in this case means building a response object to return from the call).
e.g.
try {
$objectBeingStubbed->doSomething();
} catch (\Exception $ex) {
if ($ex instanceof CustomExceptionType) {
$this->_errorResponse->error->message = $exception->getMessage();
$this->_errorResponse->error->code = $exception->getCode();
$this->_errorResponse->error->data = $exception->getData();
} else {
throw $ex;
}
}
I'm attempted to simulate the exception being thrown with:
$objectStub->expects($this->any())
->method('doSomething')
->will($this->throwException(new CustomExceptionType()));
But when the exception arrives in the class I'm testing it's now an instance of "Mock_ErrorResponse_????" which doesn't extend my custom exception. My exception is instead contained in a "$exception" property on the Mock_ErrorResponse.
Is there any way of handling this without being forced to do something horrible like:
if ($ex instanceof PHPUnit_Framework_MockObject_Stub_Exception) {
$ex = $ex->exception;
}
if ($ex instanceof CustomExceptionType) {
...
Inside the class I'm testing?

First of all, instead:
} catch (\Exception $ex) {
if ($ex instanceof CustomExceptionType) {
you should use try/catch structure:
// (...)
} catch (CustomExceptionType $e) {
// (...)
} catch (\Exception $e) {
// (...)
}
So, answering your question, basically probably you're doing sth wrong. Because when the stubbed method throws an exception, it should throw exactly exception that you've set with throwException method.
I don't know how you build your stub (maybe there something is broken, maybe namespaces) but please consider an example below which works fine.
class Unit
{
public function foo()
{
throw new \InvalidArgumentException();
}
public function bar()
{
try {
$this->foo();
} catch (\InvalidArgumentException $e) {
return true;
} catch (\Exception $e) {
return false;
}
return false;
}
}
class UnitTest extends \PHPUnit_Framework_TestCase
{
public function testBar()
{
$sut = $this->getMock('Unit', array('foo'));
$sut->expects($this->any())
->method('foo')
->will($this->throwException(new \InvalidArgumentException()));
$this->assertTrue($sut->bar());
}
}
Of course you can replace InvalidArgumentException with your own implementation exception and this still should work. If you'll still have problems with figure out what is wrong with your code please post more complete example (eg. how you build your stub). Maybe then I can help more.

Nowadays you can use the #expectedException php-doc annotation built-in in PHPUnit: https://phpunit.de/manual/current/en/writing-tests-for-phpunit.html#writing-tests-for-phpunit.exceptions
/**
* #expectedException InvalidArgumentException
*/
public function testBar()
{
$sut = $this->getMock('Unit', array('foo'));
$sut->expects($this->any())
->method('foo')
->will($this->throwException(new \InvalidArgumentException()));
}

Related

Laravel is throwing exception event when I have try, catch

I am using laravel 5.4. I have a method in a class that gets a new instance of a model class. The class's full name is computed at run time, so there is a chance the computed class name does not exists. In the case the class does not exists, I want to ignore any exception and I want to return null instead.
But, when an exception takes place, Laravel still throw the exception below even thought I believe it should not
[Symfony\Component\Debug\Exception\FatalThrowableError]
Class 'App\Models\CreatedBy' not found
Note that the string App\Models\CreatedBy was computed at run-time.
Here is my code
private function getForeignModelInstance()
{
try {
if (!$this->foreignModel) {
$model = $this->getFullForeignModel();
if ($model) {
$this->foreignModel = new $model();
}
}
return $this->foreignModel;
} catch (\Exception $e) {
return null;
}
}
How can ignore any error thrown and settle by returning null?
I think the best way is to prevent exception happen instead of hiding it. So before make a new class instance, check if its exists:
private function getForeignModelInstance()
{
try {
if (!$this->foreignModel) {
$model = $this->getFullForeignModel();
if ($model && class_exists($model)) {
$this->foreignModel = new $model();
}
return null;
}
return $this->foreignModel;
} catch (\Exception $e) {
return null;
}
}
Note: class_exists will not work using the short, aliased class name.

PHP: how to get all defined variables inside exception_handler

I'm working on a exception logging script, I use set_exception_handler() to handle uncaught exception.
Inside my custom exception handler, I use get_defined_vars() but it only return an array with a exception object, every variables created before exception thrown were disappear
$testing_var = 'testtesttest';
try {
throw new Exception("Error Processing Request");
} catch (Exception $e) {
var_dump(get_defined_vars()); // this could get $testing_var
}
set_exception_handler('exception_handler');
function exception_handler(exception)
{
var_dump(get_defined_vars()); // no, it can't get $testing_var, exception object only
}
throw new Exception("Error Processing Request");
In the scope where you are calling get_defined_vars() the variable you are after is not defined, so of course it will not be returned. from the docs:
This function returns a multidimensional array containing a list of all defined variables, be them environment, server or user-defined variables, within the scope that get_defined_vars() is called.
What are you trying to achieve? In general you should pass all information needed to handle the exception to the exception when constructing it. possibly using a custom exception class:
<?php
// custom exception class
// could be extended with constructor accepting an optional context
class ContextAwareException extends Exception
{
private $context;
public function setContext($context)
{
$this->context = $context;
}
public function getContext()
{
return $this->context;
}
}
function exception_handler($exception)
{
if ($exception instanceof ContextAwareException) {
$exception->getContext();
} else {
// we have no context
}
}
/*
* using this exception
*/
$testing_var = 'testtesttest';
$exception = new ContextAwareException("Error Processing Request");
$exception->setContext(get_defined_vars());
throw $exception;
I have found an alternate way to do this. I'm also looking for exception solution but this one works for me. If you use errors instead of exceptions - it seems to work.
set_error_handler('test','handler');
class test {
public static function handler($code, $error, $file = NULL, $line = NULL) {
throw new Exception($error, $code, 0, $file, $line);
return true;
}
}
$testVar='carolines';
try {
trigger_error('megamsg');
}
catch(Exception $e) {
var_dump($e);
$vars=$E BLABLABLA
}
Find yourself how to extract from $e. But if you debug You will see in trace handler function call with $testVar variable

How to prevent further execution of class if something fails in constructor

How to prevent further execution of class if something fails in constructor.
........Worker.php..............
class Worker {
public function __construct() {
try {
$this->pheanstalk = new Pheanstalk('127.0.0.1');
}
catch (Exception $e) {
logFatal('Pheanstalk: '.$e->getMessage());
}
}
.............
.............
.............
.............
}
.
............processing.php..........
require_once ROOTPATH.'worker.php';
$worker = new worker();
$worker -> put($Data);
.............
.............
.............
.............
Now if the try block fails in the constructor i dont want to execute put() but rest of code should continue in processing.php
new Pheanstalk('127.0.0.1'); throws a exception which is caught by catch.
Best solution is to catch the exception outside your class. Not only can you skip the put, logging errors is also not really the responsibility of that class anyway. Oh and Unit testing is easier too!
class SomeClass
{
public function __construct()
{
if ($somethingFails === true)
throw new Exception();
}
}
try {
$instance = new SomeClass();
$instance->put();
} catch (Exception $exception) {
// Handle here
logFatal('Pheanstalk: '.$e->getMessage());
}
If it's another piece of application throwing the exception, and your constructor is wrapped around it. Consider catching the exception, and then throwing your own.
Why don't you throw an exception in the constructor?
See http://php.net/manual/en/language.exceptions.php

php exceptions: should exception be rethrown

UPDATE:
I want to do something like this: http://framework.zend.com/wiki/display/ZFDEV2/Proposal+for+Exceptions+in+ZF2
thats way I need every separate exceptions for each framework component
<?php
class ClassA {
public function doSomething() {
throw new ClassA\Exception\BadMethodCallException('bad method called');
}
}
class Application {
public function MainMethod() {
$ClassA = new ClassA();
$ClassA->doSomething();
}
}
try {
$Application = new Application();
$Application->MainMethod();
} catch(\Application\Exception $e) {
// exception cannot be catched, because ClassA\Exception\BadMethodCallException was thrown
}
?>
In my framework eatch components has its own exception classes. So, is it logical that Application throws ClassA exception or should I catch ClassA\Exception\BadMethodCallException in MainMethod and rethrow as Application\Exception\BadMethodCallException like this:
<?php
class Application {
public function MainMethod() {
$ClassA = new ClassA();
try {
$ClassA->doSomething();
} catch(\ClassA\Exception\BadMethodCallException $e) {
throw new Application\Exception\BadMethodCallException('message', null, $e);
}
}
}
?>
I don't have much of a solution for your problem, but having an Exception Class for each part of your App is a bad way to go in my opinion. It doesn't make much sense.
I would just work with the error codes and identify the "Exception thrower" by that.

Should I rethrow an exception in this case?

Is this approach ok? Am I handling exceptions correctly? See my class:
class Email extends String
{
protected function validate($email)
{
try{
parent::validate($email);
} catch(InvalidArgumentException $e) {
throw $e;
}
if(!filter_var($value,FILTER_VALIDATE_EMAIL))
{
throw new InvalidArgumentException('etc.');
}
}
}
If you are not going to do anything with the exception within that catch block, it's not necessary to enclose that parent method call in its own try-catch block. The method will automatically pass the exception up from the parent's implementation if it encounters one outside a try-catch block, just like if you threw an exception from the same context (as you do after your if condition):
protected function validate($email)
{
parent::validate($email);
if (!filter_var($value, FILTER_VALIDATE_EMAIL))
{
throw new InvalidArgumentException('etc.');
}
}

Categories