Test a method which throws an exception using Junit - java

I am trying to write a test case for a method which throws an exception based on certain logic. However the test case fails as the expected exception and obtained exceptions are different.
Method to test -
public void methodA (//parameters) throws ExceptionA
{
certainlogic=//call some method
if (certainlogic)
throw new ExceptionA(//exception details)
else
//code snippet
}
Test method -
#Test (expected=ExceptionA.class)
public void testMethodA
{
try
{
when (//mock method).thenReturn(true);
//call methodA
}
catch (ExceptionA e)
{
fail(e.printStackTrace(e));
}
}
I am receiving the below error -
Unexpected exception, expected<cExceptionA> but was<java.lang.AssertionError>
How do I solve this issue?

You have to remove the catch in your test
#Test (expected=ExceptionA.class)
public void testMethod()
{
when (//mock method).thenReturn(true);
//call methodA
}
Otherwise you catch the ExceptionA and by calling fail you throw an AssertionError. Obviously the AssertionError is not an ExceptionA and therefore your test fails.

You should remove the try-catch block entirely or at least the catch.
The "expected = ExceptionA.class" tells junit to monitor for thrown exceptions, catch them and compare their class against the given class.
If you catch the thrown exception, the #Test-annotated junit method cannot detect if such an exception is thrown.
By calling fail(...) you implicitly throw an AssertionError which junit detects and thus your test fails because AssertionError.class != ExceptionA.class

Related

Why does this test succeed regardless whether an exception is thrown or not?

When I remove the try/catch it works but cannot test negative test
public class TileCombinationSetsTest {
#Test public void testTileCombinations() {
new TileCombinationSets();
assertEquals(TileCombinationSets.tileCombinations(1).size(), 7);
assertEquals(TileCombinationSets.tileCombinations(2).size(), 42);
assertEquals(TileCombinationSets.tileCombinations(3).size(), 210);
assertEquals(TileCombinationSets.tileCombinations(4).size(), 840);
assertEquals(TileCombinationSets.tileCombinations(5).size(), 2520);
assertEquals(TileCombinationSets.tileCombinations(6).size(), 5040);
assertEquals(TileCombinationSets.tileCombinations(7).size(), 5040);
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Throwable e) {}
}
}
In JUnit a test fails when the test method throws an exception (or an other Throwable). JUnit's test runner catches the exception and reports the test as failed. On the other hand the test runner considers a test to be successful when the test method finishes without throwing an exception. Statements like assertEquals and fail throw an AssertionError.
In your test fail("Exceptions expected") is throwing an AssertionError. which is immediately caught and and therefore the test method testTileCombinations doesn't throw an exception. Now for JUnit it looks like the method was executed successfully and therefore it considers the test to be successful.
If you want to test that TileCombinationSets.tileCombinations(4) throws an exception then you can use JUnit's assertThrows
assertThrows(
Exception.class, // you can be more specific here
() -> TileCombinationSets.tileCombinations(4)
);
If you want to test that TileCombinationSets.tileCombinations(4) doesn't throw an exception then you simply execute it. (JUnit will report the test as failed if it throws an exception and successful otherwise.)
#Test
public void testTileCombinations() {
...
TileCombinationSets.tileCombinations(4);
}
I assume the part
TileCombinationSets.tileCombinations(4)
throws an exception the second time it is executed.
You could print the stacktrace of the exception to see if an exception is thrown.
Without knowing what TileCombinationSets.tileCombinations(int x) does its hard to say.
If possible could you post the method?
You should generally not catch Throwable but Exception instead. Throwable also includes subclasses of Error, which are critical errors concerning that Java Runtime Environment itself (like OutOfMemoryError), from which a program should not attempt to recover because it puts the program into an undefined state.
As it happens, the AssertionError that is thrown by the fail() method in your example
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Throwable e) {}
also extends Error.
So by changing your code to
try {
TileCombinationSets.tileCombinations(4);
fail("Exceptions expected");
}
catch(Exception e) {}
it should behave as intended, as long as the exceptions thrown by your tileCombinations() method only extend Exception (which they should, as it is bad practice to extend Error yourself).

Mockito catch exception in void method

I have this method:
public void deleteTableEsiti() throws Exception {
try{
EsitiDAO esitiDAO = new EsitiDAO();
int deletedEsiti = esitiDAO.deleteTableEsiti(em);
}
catch(Exception e ){
log.error(e);
}
finally{
em.close();
}
}
I'm trying to make the test that cover the catch exception. I have tried many times but I can't cover that lines with Mockito.
This is the test that i have write:
#Test(expected=Exception.class)
public void mockException(){
ServiceG service = Mockito.mock(ServiceG.class);
try {
Mockito.doThrow(Exception.class).when(service).deleteTableEsiti();
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
};
//Mockito.when(service.deleteTableEsiti()).thenThrow(new Exception());
}
I have always this error:
[ERROR] Failures:
[ERROR] JUnit.mockException Expected exception: java.lang.Exception
and lines are not covered by test.
Firstly, your method deleteTableEsiti() never throws any exception. It catches it and logs it, but always returns normally. If you want your method to throw an exception, don't catch it, or catch it and throw a custom exception that wraps the original exception.
Your unit test does not actually call the mocked method deleteTableEsiti() anyway, since all it does is set up a mock rule to throw an exception when the method is called (which you never call).
So, after calling Mockito.when, you should call (or do something that calls) that method in your unit test.

How to unit test both cases of a void validate method?

I am writing a void validate method like this one:
void validate(SomeObject someObject) {
if (check someObject with constraints) {
throw new SomeException();
}
}
To unit test this method, I would like to test both legal and illegal input:
for illegal input, I used (expected = SomeException.class)
I am wondering how we could test the case when someObject is legal?
Legal in this case means that the validation completes without exceptions. To test it you just need to call validate.
#Test
public void testLegal() throws SomeException {
validator.validate(/* some legal object*/);
}
This test will fail only if an exception is thrown during validation.
1st Test Case :
#Test
public void testOK() throws Exception {
validate(someObject);
// At Least 1 assertion
}
2nd Test Case :
#Test(expected=SomeException.class)
public void testException() throws Exception {
try {
validate(someObject);
} catch(SomeException e) {
// At Least 1 assertion
throw e;
}
}
In this 2nd test case, if the exception is not thrown, the test will fail because it expects SommeException.class.
At least 1 assertion is mandatory because you must verify that the exception that has been thrown is well the one you were expected.
To test the case where someObject is legal, just call validate in a try block. If an exception is thrown, fail the test. If no exception is thrown, let the test end normally and pass, since that is the expected behavior.
Example would look something like:
#Test
public void myTest() {
try {
validate(new SomeObject());
} catch (Exception e) {
fail("expected no exception, but one was thrown.");
}
}

How to test a code with Mockito that captures an Exception and returns false

I know there are several ways to use Mockito in order to test whether a certain exception was thrown. But, my problem is that the method I am trying to test does NOT raise any exception. Rather, my method has a try-catch clause and within the catch clause it simply returns false AFTER capturing an exception. How do I test my method?
boolean method() throws DataException {
try {
a.do();
return true;
} catch(NullPointerException e) {
/* Come down here when a is null */
return false;
}
}
To give it a little more twist, method() is forced to throw DataException since the do() method throws DataException.
So, I have two issues:
I must throw DataException from within my test code
I must test method() to see whether it captures NullPointerException and returns false.
Editing. Yes, a is a mocked object.
You can mock object a and throw a NullPointerException
#Test
public void itShouldReturnFalse
when(a.do()).thenThrow(new NullPointerException());
assertFalse(yourClass.method());
}
#Test(expected = DataException.class)
public void itShouldThrowException() {
when(a.do()).thenThrow(new DataException());
yourClass.method();
}

how to handle exceptions in junit

I wrote some test cases to test some method. But some methods throw an exception. Am I doing it correctly?
private void testNumber(String word, int number) {
try {
assertEquals(word, service.convert(number));
} catch (OutOfRangeNumberException e) {
Assert.fail("Test failed : " + e.getMessage());
}
}
#Test
public final void testZero() {
testNumber("zero", 0);
}
If I pass -45, it will fail with OutOfRangeException but I am not able to test specific exception like #Test(Expected...)
An unexpected exception is a test failure, so you neither need nor want to catch one.
#Test
public void canConvertStringsToDecimals() {
String str = "1.234";
Assert.assertEquals(1.234, service.convert(str), 1.0e-4);
}
Until service does not throw an IllegalArgumentException because str has a decimal point in it, that will be a simple test failure.
An expected exception should be handled by the optional expected argument of #Test.
#Test(expected=NullPointerException.class)
public void cannotConvertNulls() {
service.convert(null);
}
If the programmer was lazy and threw Exception, or if he had service return 0.0, the test will fail. Only an NPE will succeed. Note that subclasses of the expected exception also work. That's rare for NPEs, but common with IOExceptions and SQLExceptions.
In the rare case that you want to test for a specific exception message, you use the newish ExpectedException JUnit #Rule.
#Rule
public ExpectedException thrown= ExpectedException.none();
#Test
public void messageIncludesErrantTemperature() {
thrown.expect(IllegalArgumentException.class);
thrown.expectMessage("-400"); // Tests that the message contains -400.
temperatureGauge.setTemperature(-400);
}
Now, unless the setTemperature throws an IAE and the message contains the temperature the user was trying to set, the test fails. This rule can be used in more sophisticated ways.
Your example can best be handled by:
private void testNumber(String word, int number)
throws OutOfRangeNumberException {
assertEquals(word, service.convert(number));
}
#Test
public final void testZero()
throws OutOfRangeNumberException {
testNumber("zero", 0);
}
You can inline testNumber; now, it does not help much. You can turn this into a parametrized test class.
Remove the try-catch block and add throws Exception to your test method, like:
#Test
public final void testZero() throws Exception {
assertEquals("zero", service.convert(0));
}
JUnit expects failing tests will throw Exceptions, your catching them is just stopping JUnit from being able to report them properly. Also this way the expected property on the #Test annotation will work.
You don't need to catch the exception to fail the test. Just let it go (by declaring throws) and it will fail anyway.
Another case is when you actually expect the exception, then you put fail at the end of try block.
For example:
#Test
public void testInvalidNumber() {
try {
String dummy = service.convert(-1));
Assert.fail("Fail! Method was expected to throw an exception because negative numbers are not supported.")
} catch (OutOfRangeException e) {
// expected
}
}
You can use this kind of test to verify if your code is properly validating input and handles invalid input with a proper exception.
There are several strategies that are open to you to deal with expected exceptions in your tests. I think the JUnit annotations and try/catch idiom have already been mentioned above. I'd like to draw attention to the Java 8 option of Lambda expressions.
For instance given:
class DummyService {
public void someMethod() {
throw new RuntimeException("Runtime exception occurred");
}
public void someOtherMethod(boolean b) {
throw new RuntimeException("Runtime exception occurred",
new IllegalStateException("Illegal state"));
}
}
You can do this:
#Test
public void verifiesCauseType() {
// lambda expression
assertThrown(() -> new DummyService().someOtherMethod(true))
// assertions
.isInstanceOf(RuntimeException.class)
.hasMessage("Runtime exception occurred")
.hasCauseInstanceOf(IllegalStateException.class);
}
Take a look at this blog which covers most of the options with examples.
http://blog.codeleak.pl/2013/07/3-ways-of-handling-exceptions-in-junit.html
And this one explains the Java 8 Lambda option more fully:
http://blog.codeleak.pl/2014/07/junit-testing-exception-with-java-8-and-lambda-expressions.html

Categories