Team
Team

Reputation: 557

Try Catch block works but test assertThrows fail (Junit 5)

I am trying to follow this tutorial JUnit 5: How to assert an exception is thrown?

I use Java 10, IntelliJ 2018 and Junit 5.

I make a calculator app that adds 2 fractions. It checks whether the input has 0 in the denominator.

When I run the test The exception Message get printed out "Undefined Math Expression" but my IDE says "Expected java.lang.Throwable to be thrown, but nothing was thrown." I think there is some problem with the scope of my code? I'm a newbie, please be kind. I provided the code and the test below:

public class Calculator {
    public static int[] calculate (int firstNumerator, int firstDenominator, int secondNumerator, int secondDenominator) {

        String exceptionMessage = "Undefined Math Expression";
        int resultNumerator;
        int resultDenominator;
        int[] result = new int[2];

        resultNumerator =  (firstNumerator * secondDenominator) +
                (secondNumerator * firstDenominator);
        resultDenominator = firstDenominator * secondDenominator;

        try {
            if (resultDenominator == 0) {
                  throw (new Throwable(exceptionMessage));
            } else {
                result[0] = resultNumerator;
                result[1] = resultDenominator;
            }
        } catch (Throwable e) {
           System.out.println(e.getMessage());
        }

        return result;
    }
}

The test:

class CalculatorTest {
    @Test
    void denominatorContainsZero() {
        assertThrows(Throwable.class, () -> {
            Calculator.calculate(0,0,0,0);
        });
    }
}

Upvotes: 3

Views: 13328

Answers (3)

ROHIT IHARE
ROHIT IHARE

Reputation: 46

You are not actually throwing exception, you are catching it. For this to work, you should remove try catch block.

Upvotes: 2

Andy Turner
Andy Turner

Reputation: 140318

The misunderstanding here appears to be in what JUnit can actually see.

JUnit isn't magical: it's just plain old Java. It can't see inside your methods to see what they are doing. All it can see is what any other code can see when it executes a method: the return value and uncaught exceptions (as well as any side effects of the method, if they are visible to the calling code).

Your method here doesn't throw an exception from the perspective of a caller: internally, it throws the exception, but it catches and handles it.

If you want JUnit to test that an exception is thrown, you need to not catch that exception.

It is never (*) the right thing to do to throw an exception and then catch and handle it yourself. What's the point? You can simply do the thing you do to handle it, without throwing the exception. Exceptions are expensive to throw, because of the need to capture the entire stack trace.

Throwable is never (*) the right exception to throw. It's the exception "equivalent" of returning Object: it conveys no type information about the exception to the caller, who then either has to do a lot of work to try to handle it; or, more realistically, should just propagate it themselves. IllegalArgumentException is the right exception to throw here, if you actually needed to throw (and not catch) an exception.

Throwable is rarely the right thing to catch. Throwable is a supertype of both Exception and Error, so you might unintentionally catch an Error, like OutOfMemoryError, which shouldn't be caught because there is nothing reasonable to do except crash your program. Catch the most specific type you can; which also means that you should throw the most specific type you can (or, at least, a type appropriate to the abstraction).


(*) This is "never" as in "ok, there are a limited number of circumstances where it may be appropriate". But unless you understand what these are, don't.

Upvotes: 9

xingbin
xingbin

Reputation: 28279

The Throwable is catched by try catch block, so Junit can not access it. Try remove the try catch block.

Upvotes: 6

Related Questions