Reputation: 14046
I've written some automation tests where I use syntax like -
try {
// Test case steps and validations
} finally {
// Clean up related to test
}
NOTE: This does not have catch
block as my tests do not expect exceptions.
If test fails in try
as well as finally
block, only failures of finally
are returned on console but not of try
. Simple example here(TestNG is used here for assertions) -
try {
Assert.assertEquals(true, false, "Boolean values did not match");
} finally {
Assert.assertEquals(100, 10, "Integer values did not match");
}
In this case, only details of finally failures are returned.
This does not help to identify actual failure of test looking at the console.
I would like to understand why Java does not return both failure details on console which can help user to identify failure cause at very first look.
Upvotes: 4
Views: 80
Reputation: 159096
That is because a new exception thrown from a finally
block replaces the exception thrown from the try
block, as documented in the Java Language Specification, section 14.20.2. Execution of try-finally and try-catch-finally:
If execution of the
try
block completes abruptly because of athrow
of a valueV
, then there is a choice:[...]
If the
finally
block completes abruptly for reasonS
, then thetry
statement completes abruptly for reasonS
(and thethrow
of valueV
is discarded and forgotten).
Since the finally
block doesn't even know of the original exception, it cannot do anything about it.
However, if you catch
the original exception, you can include it as a suppressed exception (Java 7+), but it's a bit convoluted:
AssertionError originalError = null;
try {
Assert.assertEquals(true, false, "Boolean values did not match");
} catch (AssertionError e) {
originalError = e;
throw e;
} finally {
try {
Assert.assertEquals(100, 10, "Integer values did not match");
} catch (AssertionError e) {
if (originalError == null)
throw e;
originalError.addSuppressed(e);
throw originalError;
}
}
Upvotes: 1
Reputation: 44952
Because under the hood Assert.assertEquals()
uses Assert.fail()
to throw an AssertionError
to signal the error.
The exception in finally
block will replace and discard the one thrown in try
block as per 14.20.2. Execution of try-finally and try-catch-finally.
Upvotes: 1
Reputation: 271575
The same thing can be observed with throwing exceptions:
try {
throw new RuntimeException("Message 1");
} finally {
throw new RuntimeException("Message 2");
}
Here, only Message 2
is printed:
Exception in thread "main" java.lang.RuntimeException: Message 2
This is because when finally
throws an exception, any exceptions in try
is "discarded and forgotten":
JLS section 14.20.2
If the run-time type of V is not assignment compatible with a catchable exception class of any catch clause of the try statement, then the finally block is executed. Then there is a choice:
If the finally block completes normally, then the try statement completes abruptly because of a throw of the value V.
If the finally block completes abruptly for reason S, then the try statement completes abruptly for reason S (and the throw of value V is discarded and forgotten).
Upvotes: 4