Shiva Kumar
Shiva Kumar

Reputation: 3161

How to assert that an exception is caught?

I know how to assert that an Exception is thrown. But, how can I assert that an Exception was thrown and it was successfully caught? For example, say I have a method which should throw a particular type of exception for invalid inputs

public static void myMethod(String value) {
    try {
        someExternalMethod(value);// can throw IllegalArgumentException
    } catch (IllegalArgumentException e) {
        System.out.println("Let me handle it differently");
    } catch (Exception e) {
        System.out.println("Not IllegalArgumentException");
    }
}

Now I want to assert that for some values the method indeed has thrown 'IllegalArgumentException' and not some other Exception.

Upvotes: 4

Views: 7808

Answers (4)

Nick Holt
Nick Holt

Reputation: 34301

You're missing the important point of unit testing - tests should test behaviour, not implementation.

Given this assumption you should be testing the behaviour of myMethod is as expected when an IllegalArgumentException occurs. It's hard to say any more than that with the method you've shown given the parameter, a single String is immutable, there is no return value and no exceptions are thrown.

A better example might be this method (which is a little contrived to demonstrate the point):

public double divide(int numerator, int denominator)
{
  try
  {
    return numerator / denominator;
  }
  catch (ArithmeticException e)
  {
    return Double.NaN;
  }
}

Where your tests would assert that the division is correct and that when an error occurs NaN is returned, like this:

@Test
public void testDivide()
{
  assertEquals(2.0, divide(4, 2), 0);
}

@Test
public void testDivideByZero()
{
  assertTrue(Double.isNaN(divide(1, 0));
}

You could then re-write the divide method like this:

public double divide(int numerator, int denominator)
{
  if (denominator == 0)
  {
    return Double.NaN;
  }
  else
  {
    return numerator / denominator;
  }
}

And the tests would confirm the operation of my system because the behaviour of the divide method remains unchanged.

Upvotes: 1

troig
troig

Reputation: 7212

  1. Mock method someExternalMethod(value) to force throw Exception
  2. Test method myMethod, checking that is not throwing Exception:

    @Test
    public void testMyMethod() {
       try {
          myMethod("value");
       } catch (Exception ex) {
          Assert.fail();
       }
    }
    

Upvotes: 0

Sergey Kalinichenko
Sergey Kalinichenko

Reputation: 726469

In the context of testing myMethod you cannot (and more importantly, you should not want to) check that someExternalMethod has thrown IllegalArgumentException. In fact, your tests of myMethod should not assume that a call of someExternalMethod has been made: it is an implementation detail of myMethod.

The very reason myMethod catches these exceptions is to hide them from its callers. You should check that these exceptions are hidden from you by passing values that cause them, and verifying that nothing is thrown in both cases.

Testing someExternalMethod, along with the exceptions that it throws, is the task accomplished by testing someExternalMethod, not myMethod.

Upvotes: 2

user3453226
user3453226

Reputation:

catch blocks are evaluated in the order they are.

Your code works fine: in case of IllegalArgumentException, Exception block will be ignored.

Upvotes: 0

Related Questions