I am using the PHPUnit_Selenium extension and encounter some unwanted behaviour if an element does not exist:
Selenium Test Case:
$this->type('id=search', $searchTerm);
Test Output:
RuntimeException: Invalid response while accessing the Selenium Server at 'http:
//localhost:4444/selenium-server/driver/': ERROR: Element id=search not
found
So, I get an error but I would like to convert it to a failure instead
I considered this:
try {
$this->type('id=search', $searchTerm);
} catch (RuntimeException $e) {
$this->fail($e->getMessage());
}
But I don't really want to convert all runtime exceptions to failures and don't see a clean way to distinguish them.
An additional assertion would be great but I can't find one that fits my need. Something like:
$this->assertLocatorExists('id=search'); // ???
$this->type('id=search', $searchTerm);
Am I missing something? Or is there another method that I did not think about?
Used versions:
PHPUnit 3.7.14
PHPUnit_Selenium 1.2.12
Selenium Server 2.30.0
Why not do something like this:
$element = $this->byId('search');
//from https://github.com/sebastianbergmann/phpunit-selenium/blob/master/Tests/Selenium2TestCaseTest.php
In java (sorry, I use Selenium in Java) this would throw an exception if the element with id search is not found. I would check the documentation to see if it is the same behavior in php. Otherwise you can try to see if the $element is valid, eg: is_null($element)
For test cases based on SeleniumTestCase, I found the following methods to be useful:
getCssCount($cssSelector)
getXpathCount($xpath)
assertCssCount($cssSelector, $expectedCount)
assertXpathCount($xpath, $expectedCount)
For test cases based on Selenium2TestCase the solution suggested by #Farlan should work, the following methods retrieve an element and throw an exception if no element was found:
byCssSelector($value)
byClassName($value)
byId($value)
byName($value)
byXPath($value)
In my case the tests descend from SeleniumTestCase, so the solution for the example in the question was:
$this->assertCssCount('#search', 1);
Well, you could check the exception message text in the catch block, and re-throw it if it doesn't match Element id=search not found (or a suitable regex).
try {
$this->type('id=search', $searchTerm);
} catch (RuntimeException $e) {
$msg = $e->getMessage();
if(!preg_match('/Element id=[-_a-zA-Z0-9]+ not found/',$msg)) {
throw new RuntimeException($msg);
}
$this->fail($msg);
}
Not ideal, but it would do the trick.
I guess this demonstrates why one should write custom exception classes rather than re-using standard ones.
Or since it's open source, you could, of course, always modify the phpunit Selenium extension to give it a custom exception class.
Related
I am working on a PHP project that requires validating a JSON request to a predefined schema, that is available in swagger. Now I have done my research and have found that the best project for this is SwaggerAssertions:
https://github.com/Maks3w/SwaggerAssertions
Within SwaggerAssertions/tests/PhpUnit/AssertsTraitTest.php, I would love to make use of the testAssertRequestBodyMatch method, where you do this:
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
This assertion above does exactly what I need, but if I pass a invalid request it causes a fatal error. I want to trap this and handle the response back rather than the app quitting altogether.
How can I make use of this project, even though it looks like its all for PHPUnit? I am not too sure how one would make use of this project in normal PHP production code. Any help would be greatly appreciated.
Assertions throw exceptions if the condition is not met. If an exception is thrown, it will stop all following code from being executed until it's caught in a try catch block. Uncaught exceptions will cause a fatal error and the program will exit.
All you need to do to prevent your app from crashing, is handling the exception:
try {
self::assertRequestBodyMatch($request, $this->schemaManager, '/api/pets', 'post');
// Anything here will only be executed if the assertion passed
} catch (\Exception $e) {
// This will be executed if the assertion,
// or any other statement in the try block failed
// You should check the exception and handle it accordingly
if ($e instanceof \PHPUnit_Framework_ExpectationFailedException) {
// Do something if the assertion failed
}
// If you don't recognise the exception, re-throw it
throw $e;
}
Hope this helps.
This is a general question regarding exception handing for exceptions thrown in onther people's code.
I am using the following Codeigniter PHP library: https://github.com/sepehr/ci-mongodb-base-model
which relies upon this library for MongoDB: https://github.com/alexbilbie/codeigniter-mongodb-library/tree/v2
If I call a function in the first library, and it then calls one from the second. Sometimes the second library throws exceptions which I want to be able to deal with in my own code, but there is a try-catch statement around the exception throwing call, which means that it is dealt with before I get a chance to (I just prints the exception to the screen).
My question is:
Without modifying all of the functions in the first and second libraries (i.e. removing all of the try catches), how can I deal with the exception that is thrown?
EDIT
This is how the functions in the second library are arranged:
class SomeClass
{
function do_something()
{
...
try {
...
}
catch {
$this->_show_error('Update of data into MongoDB failed: ' . $exception->getMessage(), 500);
}
}
function _show_error($error_message = '', $response_code = 500)
{
//Inbuilt Codeigniter helper function which can be disabled from printing the error to the screen
show_error($error_message, $response_code);
}
}
Although I can disable the error from being printed (which is of course just for debugging), I still have no way of knowing that it occurred and handling it.
(should be a comment rather than an answer, but it's a bit long)
just prints the exception to the screen
Really? Are you sure?
Did you check it doesn't trigger an error instead of an exception and you're running this on a system which is not configured as a production server?
If so then I'd steer way clear of this as a library.
(I sincerely doubt anyone would write code that dumb and publish it without lots of warnings)
PHP 5.5 is adding support for finally in try/catch blocks.
Java allows you to create a try/catch/finally block with no catch block, so you can cleanup locally when an exception happens, but let the exception itself propagate up the call stack so it can be dealt with separately.
try {
// Do something that might throw an exception here
} finally {
// Do cleanup and let the exception propagate
}
In current versions of PHP you can achieve something that can do cleanup on an exception and let it propagate, but if no exception is thrown then the cleanup code is never called.
try {
// Do something that might throw an exception here
} catch (Exception $e) {
// Do cleanup and rethrow
throw $e;
}
Will PHP 5.5 support the try/finally style? I have looked for information on this, but the closest I could find to an answer, from PHP.net, only implies that it doesn't.
In PHP 5.5 and later, a finally block may also be specified after the
catch blocks. Code within the finally block will always be executed
after the try and catch blocks, regardless of whether an exception has
been thrown, and before normal execution resumes.
The wording suggests that you're always expected to have a catch block, but it doesn't state it outright as far as I can see.
Yes, try/finally is supported (RFC, live code). The documentation is indeed not very clear and should be amended.
I've implemented a test case on a 5.5RC3 server.
As you can see in the code, it works as expected. Documentation is indeed wrong at this point.
Building upon a question I already asked regarding exceptions, I fear that I might be writing php functions wrong then, or abusing the use of exceptions. The reason I say this, is because if custom exceptions are to be caught using try/catch blocks then the following function:
public function get_specific_page($page) {
if (!is_array( $this->_page )){
throw new AisisCore_Template_TemplateException( "<div class='error'>Trying to get a property from a non array.</div>" );
}
return $this->_page[$page];
}
Would then be called such as:
try{
get_specific_page($page);
}
catch(Exception $e){
echo $e->getMessage();
}
The problem with this approach is that I have many functions that are written like this, either checking to see if a file exists, throwing an error. Checking to see if a value is set in an array, throwing an error and my issue is that the file which deals with these function calls may become over loaded with try catch.....
So my question is, how would I better write functions like this so that I don't have php files over loaded with try catch statements, yet still be able to have y own custom functions.
Is it as obvious as writing the try catch inside the function it's self?
The reason I ask, if because I am use to working with fameworks and in companies where we write our functions as you see above. How ver I have worked with code bases that have tons of these functions and I dont see half the files that are useing them doing a bunch of try catches...
Update:
I was looking through zend source to better understand exceptions and came across this:
public function setMessage($messageString, $messageKey = null)
{
if ($messageKey === null) {
$keys = array_keys($this->_messageTemplates);
foreach($keys as $key) {
$this->setMessage($messageString, $key);
}
return $this;
}
if (!isset($this->_messageTemplates[$messageKey])) {
require_once 'Zend/Validate/Exception.php';
throw new Zend_Validate_Exception("No message template exists for key '$messageKey'");
}
$this->_messageTemplates[$messageKey] = $messageString;
return $this;
}
You can see how they throw a new exception message near the bottom, this function is not called by doing:
try{}catch(){}
yet when it throws an exception, there is no issue with "uncaught exception with message"
In my opinion, your approach is correct in general. However, a few notes:
You should refrain from using HTML formatting in exception messages. Generally, you don't know how the exception that you throw will be handled. For example, an exception handler could just write the message to a log file (you don't want HTML formatting then), present it to the user in a special error view (in which case the view itself should contain the HTML formatting), or simply ignore it (no need for formatting then, anyway).
Catch only exceptions that you can handle. If you know that your function throws an AisisCore_Template_TemplateException, you should just catch that exception and let all other exceptions bubble up to an exception handler that can handle them. You can use set_exception_handler to define such an exception handler that catches all uncaught exceptions by default (this is probably the case in your example from Zend Framework). Plainly put: Only catch exceptions in places where you know how to handle them.
Only use exceptions as what the name implies: to handle (unexpected) exceptions in your control flow. Using exceptions to control the regular flow of your program is possible, but generally considered bad design (just as a side note, your code samples look alright).
For the sake of completeness, some alternatives to using exceptions:
Use return codes instead of exceptions. This is old-school C-style. The advantage is that you don't need to wrap statements with try/catch-statements. However, you have to check the return values of each procedure, which is easy to forget. When using exceptions on the other hand, you reduce the risk of unexpected errors, since uncaught exceptions produce a fatal error per default.
Use PHP errors. See the trigger_error function for this. Custom errors are however nearly impossible to catch in PHP (except by using set_error_handler, which only works at global level).
Few days ago I deal with errors like this...
exit( 'Error!' );
or exit( 'Error!' );
Doh, right? =] Now I'm trying to learn Exceptions. This is how far I got...
http://pastie.org/1555970
Is that correct use of them? It would be cool that I can have more info about 'em. Like file where exception is thrown and line of that file. I know that there are build-in methods (in Exception class), but I want to somehow extend it so I don't need to write...
throw new My_Exception( '...' );
catch( My_Exception $e ) {
echo $e->my_method();
}
...but use old syntax.
throw new Exception( '...' );
catch( Exception $e ) {
echo $e->getMessage();
}
...or maybe you have any greater thought of Exceptions? How to deal with them? Help me! =]
In general you only need to echo/log exceptions, that cannot be otherwise handled. This pretty much means, that if you put your entire application within try block, there's only one place where you need to put echoing/logging logic (i.e. the catch block associated with the outermost try block).
If on the other hand the exception can be handled without stopping the application (in your example this could be providing a default numeric value, instead of incorrect value), then there's usually no need to echo/log it.
If you do want to log such exceptions (for debugging for example), then your application should contain a logging framework, so that it's enough to do in your catch blocks something like
} catch (Exception $e) {
ExceptionLogger::log($e); //static method == ugly, but it's for simplicity in this example
// do whatever needs to be done
}
log() method above would check if the logging is enabled, and if it is savenecessary data to a file.
Exceptions should be typed based upon the error that you find. The Spl Exceptions are a good start, but you really should be creating your own exceptions as well. Some common ones that I use:
FileNotFoundException extends RuntimeException <- self explanatory
HTTPException extends RuntimeException <- Used for http classes when a non-200 result is encountered
DatabaseQueryException extends LogicException <- Used for database query errors
Now, by typing them specifically, it lets you handle the errors in your code. So let's say that you want to fetch a HTTP resource. If that fails with anything but a 404, you want to try a backup URL. You could do that with:
try {
return getHttp($url1):
} catch (HttpException $e) {
if ($e->getCode() != 404) {
try {
return getHttp($url2);
} catch (HttpException $e2) {
//It's ok to ignore this, since why know it's an HTTP error and not something worse
return false;
}
} else {
return false;
}
}
As far as your example code that you posted, I would change a few things:
Change the thrown exception to InvalidArgumentException since it has more semantic meaning (I almost never throw a raw exception).
You should try to avoid catch(Exception $e) at all costs. You have no idea what exception was thrown, so how can you possibly handle it?
Only catch exceptions that you are reasonably sure you know how to handle (and outputting an error/logging is not handling, it's removing the usefulness of the exception). You should never see something like catch($e) { logerror($e); } or catch($e) { print $e->getMessage(); } since netiher is actually handling the exception.
If you don't fix or workaround the cause of the exception in your catch block, you should re-throw it. Let the code above you in the stack try to handle it. This is especially true with libraries and classes that are reused all over the place.
Now, with user interfaces, it may be acceptable to catch the exception and show the user an error message. So your example where you print the exception's message might be ok, but you'd really need to think about the use-cases of it. Are you calling it from a model or controller? If so, it may be ok display an error message. Are you calling it from a library? If so, it's probably better to let the exception bubble up.
Also, don't use a global try{} catch() {} block. Instead, install an Exception Handler to handle it for you. It's cleaner, and more semantically correct (since any try{}catch{} implies that you know how to handle the exception that you caught, whereas the exception handler is precisely meant for exceptions that weren't handled because you didn't know how to handle them.
Exceptions are for exceptional circumstances. Do not use them for all error conditions. If a user submits a password that's too short, don't throw an exception, handle that in validation. But if your hash function is expecting sha256 to be available and it isn't, that's a time for an exception. Exceptions are useful for program errors (when a condition that is unexpected happens, such as invalid input to a function), state errors (when the application enters a state that is unknown or unstable, such as if the requested view does not exist) and runtime errors (when the application encounters an error that can only be detected at runtime, such as a file-not-found error).
There is an entire page of the PHP manual devoted to extending exceptions and that page also gives you a lot of information on the methods to identify file/line number, backtrace etc. where the exception was thrown. This is the type of information that is extremely useful for debugging.