Catch an exception only if you can handle the error
I see sometimes page methods looking like this
public void logIn(String username, String password) {
try {
WebElement emailField = wait.until(ExpectedConditions.
visibilityOfElementLocated(emailFieldBy));
emailField.click();
emailField.clear();
emailField.sendKeys(username);
WebElement passwordField = wait.until(ExpectedConditions.
elementToBeClickable(passwordFieldBy));
passwordField.sendKeys(password);
WebElement signInLink = wait.until(ExpectedConditions.
elementToBeClickable(signInLinkBy));
signInLink.click();
}
catch (Exception e) {
System.out.println("cannot log in - " + e.getMessage());
}
}
A variation of this method is with an empty catch clause:
public void logIn(String username, String password) {
try {
}
catch (Exception e) {
}
}
Or with the catch clause throwing an exception:
public void logIn(String username, String password) {
try {
}
catch (Exception e) {
throw new Exception("cannot log in - " + e.getMessage());
}
}
What is incorrect in all these cases?
In the first case, the code in the catch clause does nothing more than displaying a message. The user logging process fails and, instead of the execution being stopped, the execution continues.
The second case is similar with the first one but worse. The execution continues and not even a message is displayed.
The third case throws an exception if anything unexpected happens in the try clause. Since there are 8 lines of code in the try clause, catch uses a generic Exception parameter, stops the execution and displays a custom message and the exception message.
The third case is better than the first two since the execution is stopped.
But it is not correct to use a generic exception class when there are different exceptions that could be thrown in the try clause:
ElementClickInterceptedException
The Element Click command could not be completed because the element receiving the events is obscuring the element that was requested to be clicked.
ElementNotInteractableException
Thrown when an element is present in the DOM but interactions with that element will hit another element due to paint order.
ElementNotVisibleException
Thrown when an element is present on the DOM, but it is not visible, and so is not able to be interacted with.
StaleElementReferenceException
Thrown when a reference to an element is now "stale".
TimeoutException
Thrown when a command does not complete in enough time.
The fourth version corrects this:
public void logIn(String username, String password) {
try {
}
catch (ElementClickInterceptedException e) {
throw new ElementClickInterceptedException(
"cannot click element - " + e.getMessage());
}
catch (ElementNotInteractableException e) {
throw new ElementNotInteractableException(
"cannot interact with element - " + e.getMessage());
}
catch (ElementNotVisibleException e) {
throw new ElementNotVisibleException(
"element is not visible - " + e.getMessage());
}
catch (StaleElementReferenceException e) {
throw new StaleElementReferenceException(
"element is stale - " + e.getMessage());
}
catch (TimeoutException e) {
throw new TimeoutException("timeout exceeded - " + e.getMessage());
}
}
This is an improvement since each specific exception gets its own catch clause.
Still, this is incorrect.
Let’s go back for a moment to the goal of the try/catch statement.
try/catch statement should only be used to catch an exception if you can do error handling for it.
An exception is generated by one line of code.
Different lines of codes may generate different exceptions.
Our try clause is used for 8 lines of code. Which one may generate the exception? Any of them may do that.
Also, have a look at the catch clause. It either logs a message or throws an exception. Logging a message is not handling an error. Throwing an exception is also not handling an error.
Assuming that it is possible to handle the logging in error, how do you do this? Logging in failed. What can you do about it? Reload the page and try again? Please no.
So, it is incorrect that the try clause wraps so many lines of code.
It is incorrect to log a message or throw an exception in the catch clause.
What should we do then?
Remove the try/catch.
If the code fails, look into the root cause of the failure:
public void logIn(String username, String password) {
WebElement emailField = wait.until(ExpectedConditions.
visibilityOfElementLocated(emailFieldBy));
emailField.click();
emailField.clear();
emailField.sendKeys(username);
WebElement passwordField = wait.until(ExpectedConditions.
elementToBeClickable(passwordFieldBy));
passwordField.sendKeys(password);
WebElement signInLink = wait.until(ExpectedConditions.
elementToBeClickable(signInLinkBy));
signInLink.click();
}
Thanks for reading.