phpunit get exception message - php

I've just started with php unit.
In my test cases UsersController should return:
public function UsersController() {
....
throw new \Cake\Network\Exception\NotFoundException();
}
phpunit code
$this->setExpectedException('Cake\Network\Exception\NotFoundException');
returns an assertion failed that looks like:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
Failed asserting that exception of type "Cake\Network\Exception\NotFoundException" is thrown.
Meanwhile browser return a 404 PageNotFound and $this->assertResponseOk() returns:
App\Test\TestCase\Controller\UsersControllerTest::testActivate
exception 'Cake\Network\Exception\NotFoundException' with message 'Not Found' in /vagrant/ifmx.local/src/Controller/UsersController.php:215
Does somebody know why it's happened? And is there any way to get exception message in unit test.

You seem to have misunderstood how the integration test case works.
It doesn't just wrap a call to a controller method, like $controller->action(), it simulates a whole request, and as such, exceptions are being catched, and result in error pages being rendered, just like it happens when you are visiting a URL in your browser.
So PHPUnit will never know about the exception, and thus you cannot use the expected exception feature as you would when directly testing specific code parts where exceptions bubble up to PHPUnit. If that would happen, then it wouldn't be possible to assert responses, which one might want to do, even when an exception has been thrown.
Possible exceptions are being buffered in the IntegrationTestCase::$_exception property, which you can for example use to test if, what kind of exception has been thrown, etc, like
$this->assertInstanceOf('\Cake\Network\Exception\NotFoundException', $this->_exception);
$this->assertEquals('Not Found', $this->_exception->getMessage());

Related

PHP: Exceptions: Executing code only if the exception was thrown

assert(boolean,\Throwable) is a very handy tool for exception-proofing PHP code, but is has an annoying side effect: The second argument has to be either a string or a Throwable. That means that if you want to throw an exception, you have to new your exception on the spot. Which means that the __construct() method runs. And if the __construct() contains something such as error logging or dumping a variable to your tracking system, that's going to happen even if the assertion passes. This can result in unwanted side effects from redundant logging to stuff being rendered to your output--sometimes creating a bug where one wouldn't normally exist.
Given the tools currently available in PHP 8.1, how can someone structure an error handling system so that they can execute code in the exception ONLY WHEN the exception is actually thrown, not just when it is created?

Throwing custom exceptions without messages

I haven't uset custom exceptions before, and now it appears that I might need them but I'm not sure I understood correctly how are they supposed to be used.
Say I have a custom exception like this:
class not_found_exception extends exception{ }
Then I have a bunch of request handler functions (I think they are called controllers in the wild). And each function can throw different types of exceptions. If the URL doesn't match it throws my custom exception, the script will catch that type of exception and skip to next request handler if it's caught. But other types of exception are not supposed to be caught because they mean that the url matches but there's some other error that should be displayed.
The thing is that my custom exception doesn't need an error message because it would not show up anywhere because its supposed to be caught, but other exceptions do. So is it ok to just throw an empty not_found_exception exception?
The short answer is simply: yes. That would be ok.
For further information about best-practices regarding Exception I'll refer you to this blog. It may be written for .NET but the theories can still be applied to PHP.
https://blogs.msdn.microsoft.com/kcwalina/2007/01/30/how-to-design-exception-hierarchies/

Unit test exception-messages formatted with sprintf

How can I test if an exception throws the expected error message, when I format my error messages like this:
throw new \Exception(sprintf('Random string: "%s".', 'blablabla'));
Obviously testing with $this->assertEquals() won't work, since I don't know what %s is going to be. Is there a straight forward way to test Exception messages that use sprintf?
I believe that you should know what '%s' is going to be by triggering the part of your code you want an exception in, in a controlled way.
You could trigger the exceptions you are expecting, then you can use assertEquals with the error message you are expecting to be triggered

Magento/PHPUnit - force an exception

I'm using phpunit and the ecomdev module to unit test Magento. For a particular class the last code that needs to be tested is an exception on attempting to save a model in a try/catch. The only way I can see to get to the exception is alter the database temporarily. So I changed the table name which works, but then I have to name it back. If the test itself fails I'm in an inconsistent state.
I'd really like to get that code tested so the coverage is 100%. Otherwise I'll be wondering why it's 98% until I look at the code and remember the exception isn't tested.
I was trying to close the connection but I need it to log the exception. So I'm wondering if maybe there is something I can temporarily do to the model or resource model to cause the save to raise an exception. Something that would be reset on the next load.
One note - I can't see anyway that manipulating data will cause the exception. Again the only scenario I see causing an exception in production is if the database connection goes away.
Any ideas?
Edit:
Sample Code:
public function logStuff($stuff){
try{
Mage::getModel('my/stuff')
->setData('stuff', $stuff)
->save();
}catch(Exception $e){
Mage::helper('log/error')->logError(__METHOD__, "Could not save stuff: ". $e->getMessage());
}
}
To make test the exception catch, you need to replace your model instance with the mocked one.
It is very easy to achieve with EcomDev_PHPUnit extension:
$mockedStuff = $this->getModelMock('your/stuff', array('save'));
$mockedStuff->expects($this->once()) // How many times it is invoked
->method('save') // Wich method to mock
->will($this->returnCallback(function () {
throw new Exception('Some error text');
})); // Your exception
$this->replaceByMock('model', 'your/stuff', $mockedStuff);
Also you can evaluate your logging stuff by using mock as well.
$loggerMock = $this->getHelperMock('log/error', array('logError'));
$loggerMock->expects($this->once())
->method('logError')
->with('className::methodName', 'Could not save stuff: Some error text'); // Check that correct arguments passed
$this->replaceByMock('helper', 'log/error', $loggerMock);
Have fun with unit tests :)

Problem testing exceptions with PHPUnit and Zend Framework

When a user accesses /user/validate without the correct post parameters, my Zend application throws a zend exception. (I get the standard "An Error Occurred" message, framed within my layout). This is intentional.
I am now trying to test that behaviour with PHPUnit. Here's my test:
/**
* #expectedException Zend_Exception
*/
public function testEmptyUserValidationParametersCauseException() {
$this->dispatch('/user/validate');
}
When I run the test I get a message saying it failed, "Expected exception Zend_Exception". Any ideas?
I have other tests in the file which are working just fine...
Thanks!
The Zend_Controller_Plugin_ErrorHandler plugin handles exceptions for you and the default Error_Controller forces a 500 redirect which may mean the exception you are testing for no longer exists. Try the following unit test and see if it passes:
public function testUnknownUserRedirectsToErrorPage()
{
$this->dispatch('/user/validate');
$this->assertController('error');
$this->assertAction('error');
$this->assertResponseCode('500');
}
If this works then it shows that by the time you are rendering the error view the exception will no longer exist as it is contained in the code before the redirect.
Well, maybe it simply fails because no exception is thrown?
Did you try running the test without "#expectedException Zend_Exception"? Is there an exception at all?

Categories