I'll begin with a code example; I have to test a function, which handles data-packets. In this function, the data-packet is opened and when it doesn't contain all expected data, an InvalidParameterExeption is thrown which is logged.
public void handleData(dataPacket) {
try {
analyseData(dataPacket);
} catch (InvalidParameterException e) {
e.printStackTrace()
}
}
So, if everything goes well, my exception is printed in my terminal.
But how can I test this? I can't use this: (because the exception is caught)
#Test(expected = InvalidParameterExeption.class)
public void testIfFaultyDataPacketIsRecognised {
handleData(faultyDataPacket);
}
How can I test that the InvalidParameterExeption is thrown?
You won't catch exceptions that are not thrown. Just test the 'throwing exception' method instead of the 'exception catching' one
#Test(expected = InvalidParameterExeption.class)
public void testIfFaultyDataPacketIsRecognised() {
analyseData(faultyDataPacket);
}
Ideally you should catch and rethrow the exception.But if you dont want to do that then Why not get catch the exception in test case as expected?
#Test
public void testIfFaultyDataPacketIsRecognised () {
try {
handleData(faultyDataPacket);
Assert.fail("Fail! Method was expected to throw an exception because faulty data packet was sent.")
} catch (InvalidParameterException e) {
// expected
}
}
Related
I wrote an example which depicts my issue.
I have a simple exception:
public class TryToSpeakException extends RuntimeException {
public TryToSpeakException(String message) {
super(message);
}
}
Then I have a chain of methods that invoke each other one by one:
public class TryToSpeak {
public static void speakToPerson1() {
throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
}
public static void speakToPerson2() {
try {
speakToPerson1();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
}
}
public static void speakToPerson3() {
try {
speakToPerson2();
} catch (Exception e) {
System.out.println("speakToPerson3 caused exception");
e.printStackTrace();
}
}
static void keepSilentToPerson() {
System.out.println("Keeping silent to person 1");
}
public static void communicate() {
try {
speakToPerson3();
keepSilentToPerson(); // Why it reaches this part?
} catch (Exception e) {
System.out.println("Communication exception.");
e.printStackTrace();
}
}
public static void main(String[] args) {
communicate();
}
}
The method from the very 'bottom' throws an exception. In method communicate() after invocation of method speakToPerson3() the execution keeps going.
What i need - is to Stop execution, so that invocation of method keepSilentToPerson() is never reached and gives me the message "Communication exception.".
This is what i get in console now:
speakToPerson2 caused exception
exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
at exceptions.TryToSpeak.speakToPerson3(TryToSpeak.java:22)
at exceptions.TryToSpeak.communicate(TryToSpeak.java:36)
at exceptions.TryToSpeak.main(TryToSpeak.java:46)
Keeping silent to person 1
But if i call speakToPerson2() from my Main method like this:
public static void speakToPerson1() {
throw new TryToSpeakException("Person 1 don't wanna speak to anyone.");
}
public static void speakToPerson2() {
try {
speakToPerson1();
keepSilentToPerson();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
}
}
static void keepSilentToPerson() {
System.out.println("Keeping silent to person 1");
}
public static void main(String[] args) {
speakToPerson2();
}
I get an obvious result:
speakToPerson2 caused exception
exceptions.TryToSpeakException: Person 1 don't wanna speak to anyone.
at exceptions.TryToSpeak.speakToPerson1(TryToSpeak.java:7)
at exceptions.TryToSpeak.speakToPerson2(TryToSpeak.java:12)
at exceptions.TryToSpeak.main(TryToSpeak.java:26)
keepSilentToPerson() is not reached.
What am i doing wrong?
speakToPerson2() is catching the Exception, but you want communicate() to catch it too. Essentially, speakToPerson2() is suppressing the exception, so no other method sees it.
What you need to do is rethrow it (in both speakToPerson2() and speakToPerson3()). This is known as propagating an exception.
I.e.:
public static void speakToPerson2() {
try {
speakToPerson1();
} catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
throw e;
}
}
public static void speakToPerson3() {
try {
speakToPerson2();
} catch (Exception e) {
System.out.println("speakToPerson3 caused exception");
e.printStackTrace();
throw e;
}
}
You need to understand exactly how try-catch work. If any method in the try-catch throws an exception (one that extends/or is Exception in your example), the body of the try-catch will be interrupted to go into the catch clause.
In your case, the method speakToPerson1 will throw a TryToSpeakException. This exception will be forwarded one step above in the method call stack, the method speakToPerson2 in your case. Since the call to speakToPerson1 is surrounded with a try-catch, the catch clause is invoked and System.out.println("speakToPerson2 caused exception"); is executed. Now, the try clause encloses two methods calls, namely speakToPerson1 and keepSilentToPerson. However, since the first method throw the exception, the second is never reached and therefore keepSilentToPerson() will never by called.
Finally, think about the catching of exceptions. If you catch an exception, you are saying that you are going to handle it, by recovering or rethrowing it. If you handle it without rethrowing it, it won't be forwarded to the upper level of your call stack. Beware of this technicality
You can throw the exception after catching it speakTo* methods. This will stop execution of code in methods calling speakTo* and their catch block will be executed.
catch (Exception e) {
System.out.println("speakToPerson2 caused exception");
e.printStackTrace();
throw e;
}
You need to propagate your Exceptions to the main class to completely stop the execution of a program.
In the case 1: All your exception will be handled by speakToPerson2 function.
In the case 2: Your exception occurs at the function call of speakToPerson1, so the rest of your code will not execute.
So, inorder to stop the program from running you just have to propagate the exception, using throw keyword, in the catch block of your exception.
Suppose, I have a method:
private void someMethod() {
try {
//Do something here
}
catch (NullPointerException ex) {
System.out.println("error");
}
}
Now, I want to use this method somewhere else:
private void newMethod() {
someMethod();
JOptionPane.showMessageDialog(null, "Exception didn't occur");
}
Now, I want that if exception occurs in someMethod(), then newMethod() will not advance further, I mean, the JOptionPane message will not be shown in this case.
What will be the best way to do that? I have found a way by throwing another NullPointerException in catch block of someMethod() and then handling that from newMethod(). The code below demonstrates that:
private void someMethod() {
try {
//Do something here
}
catch (NullPointerException ex) {
System.out.println("error");
throw new NullPointerException("error");
}
}
private void newMethod() {
try {
someMethod();
JOptionPane.showMessageDialog(null, "Exception didn't occur");
}
catch (NullPointerException ex) {
System.out.println("error");
}
}
But, by this method, I am facing some difficulties for other cases. I guess there are better ways to achieve that. Thanks anyway.
You don't need to handle the exception inside someMethod. Instead you can declare the exception in this method's throws clause (if it is a checked exception) and let newMethod handle it.
private void someMethod() throws SomeCheckedException {
//Do something here
}
In case of NullPointerException, you don't need to do above, as it is an unchecked exception. Don't catch it inside someMethod, instead have try-catch inside newMethod.
It is good practice if your function intend to throw exception make it part of function declaration. So recommendation is to change someMethod() to private void someMethod() throws <exception Name>.
Depends on your requirement you can handle the exception in same method and throw another exception, or re throw same exception and handle it in another function.
In case you are re-throwing the same exception syntax is as follows:
private void someMethod() throws WhateverException {
try {
//Do something here
}
catch (WhateverException e) {
throw e;
}
}
In JUnit, using a TestWatcher and Overriding the failed() function, is it possible to remove the thrown exception and instead make my own assertion?
The use case is : with functional tests on Android, when a test makes the app crashes, I would like to replace the NoSuchElementException with an AssertionError ("app crashed").
I have no problem to make the custom assertion (when I detect a crash in finished() method) , but how to remove the thrown exception ?
Because in my report it creates for one test the exception and the assertion, so there are more failures than test in failure, which is logic but annoying.
I was wondering if there were a way to customize the Throwable object to remove the specific NoSuchElementException, manipulating the stacktrace.
I didn't manage to do it. (And necessarily I don't want to perform it using a try/catch in every tests ...).
You could override TestWatcher.apply and add a special catch for NoSuchElementException:
public class MyTestWatcher extends TestWatcher {
public Statement apply(final Statement base, final Description description) {
return new Statement() {
#Override
public void evaluate() throws Throwable {
List<Throwable> errors = new ArrayList<Throwable>();
startingQuietly(description, errors);
try {
base.evaluate();
succeededQuietly(description, errors);
}
catch (NoSuchElementException e) {
// ignore this
}
catch (AssumptionViolatedException e) {
errors.add(e);
skippedQuietly(e, description, errors);
}
catch (Throwable e) {
errors.add(e);
failedQuietly(e, description, errors);
}
finally {
finishedQuietly(description, errors);
}
MultipleFailureException.assertEmpty(errors);
}
};
}
You can do it by bypassing. An example code is given below. Hope it will help you.
try {
// Write your code which throws exception
----
----
----
} catch (NoSuchElementException ex) {
ex.printStackTrace();
if (ex instanceof NoSuchElementException) { // bypass
// NoSuchElementException
// You can again call the method and make a counter for deadlock
// situation or implement your own code according to your
// situation
AssertionError ("app crashed");
if (retry) {
---
---
return previousMethod(arg1, arg2,...);
} else {
throw ex;
}
}
} catch (final Exception e) {
e.printStackTrace();
throw e;
}
I have solved this type of issue previously. My another answer has details. You can go through my another answer: android.security.KeyStoreException: Invalid key blob
Testing a snip:
void somefunction() {
try {
aMock.doSomething();
bMock.another();
} finally {
cMock.cleanup();
}
}
Test:
#Test(expected = Exception.class)
void sometest() {
... setup various mocks ...
PowerMockito.doThrow(new Exception("abc")).when(aMock).doSomething();
outerMock.somefunction();
// ** THIS SHOULD FAIL
verify(bMock).another();
// ** THIS SHOULD FAIL TOO
verify(cMock, never()).cleanup()
}
When I run this it passes. Why? Does the throw Exception (and handling in #Test) trump the verify statements?
If so - is there some way to test that the finally clause was executed?
Because the exception is thrown (for real), everything under your function code is dead code.
outerMock.somefunction(); // throw so, this is the end
// ------- dead code blow:
// ** THIS SHOULD FAIL
verify(bMock).another();
// ** THIS SHOULD FAIL TOO
verify(cMock, never()).cleanup()
So to test the finally block you have to use a normal execution (when no exception occurs). Another solution would be to use a try/catch in the test:
try {
outerMock.somefunction();
fail("was expecting an exception..");
} catch(Exception exception) {
// ignore
}
verify(bMock).another();
verify(cMock, never()).cleanup()
To answer to the question in comments:
assuming the code is now:
void somefunction() {
try {
aMock.doSomething();
bMock.another();
} catch(Exception ex) {
cMock.handleException(ex);
}
}
the test could be:
Exception testEx = new Exception("testing")
Mockito.when(aMock.doSomething()).thenThrow(testEx);
instance.somefunction();
Mockito.verify(cMock).handleException(testEx);
Here's the code:
public class Exc {
int x = 2;
public void throwE(int p) throws Excp, Excp2 {
if(x==p) {
throw new Excp();
}
else if(x==(p+2)) {
throw new Excp2();
}
}
}
Here's the handler code:
public class tdExc {
public static void main(String[] args) {
Exc testObj = new Exc();
try {
testObj.throwE(0);
System.out.println("This will never be printed, so sad...");
} catch(Exception Excp) {
System.out.println("Caught ya!");
} catch(Exception Excp2) {
System.out.println("Caught ya! Again!!!!");
} finally {
System.out.println("This will always be printed!");
}
}
}
Excp and Excp2 both extends Exception and have similar code(nothing). Now I'm getting the error Exception has already been caught error at Excp2, regardless of whether I supply 2 or 0 to throwE method.
You're looking for:
try
{ }
catch(Excp excp)
{
log(excp);
}
catch(Excp2 excp2)
{
log(excp2);
}
finally
{ }
When you catch an exception, to specify the type of the exception, and the name of of its reference.
Your original code tried to catch Exception, which is the least specific exception, so you cannot catch anything after that.
When you are catching an exception, you have to specify what type of exception you are catching, this will allow you to better handle the exception that has occured. One thing that you have to keep in mind though, is that there is that there are specific and other more "wide purpose" exceptions.
For instance, NumberFormatException is more specific than Exception, since NumberFormatException will be thrown whenever you will try to parse a string into a number.
Thus, when having multiple catch statements, always put the most specific one on top, and the more generic ones at the end. If you put the more generic ones at the beginning, they will catch the exception before it can be passed to a more specific catch statement.
In your case, you are trying to catch the same exception twice, since you have two catch statements that try to catch the same exception.
Java dispatches to the catch() clauses based on the types of the exception: your clauses are both trying to catch an exception of type Exception, and give them the names Excp and Excp2:
public class tdExc {
public static void main(String[] args) {
Exc testObj = new Exc();
try {
testObj.throwE(0);
System.out.println("This will never be printed, so sad...");
} catch(Exception Excp) {
Shouldn't this be Excp e?
System.out.println("Caught ya!");
} catch(Exception Excp2) {
Shouldn't this be Excp2 e?
System.out.println("Caught ya! Again!!!!");
} finally {
System.out.println("This will always be printed!");
}
}
}
And, while it's unrelated, I think your earlier code would be easier for you to think about if you write it more like this:
public void throwE(boolean p) throws Excp, Excp2 {
if(p) {
throw new Excp();
} else {
throw new Excp2();
}
}
Call it with true or false as parameters.
I believe the exception can only be caught once with java. The first exception handler will process the error.
Please someone tel me if this is true for java :)