Search code examples
javaexceptionexpected-exception

Console displays exception message but is still wrong exception type -- Why?


I am attempting to create an abstract data type called bag, which essentially takes in integers with the method add(int x) and removes an arbitrary integer with the method remove().

Then, I tried to create a custom exception for the remove() method since there is a chance that removal is done when there are already no items left in the bag. Thus, I created an exception class as such:

public class EmptyBagException extends Exception {
    public EmptyBagException(String message) {
        super(message);
    }
}

and proceeded to utilise this custom exception like so:

public int remove() {

    try {
        this.realRemoval();
    } catch (EmptyBagException e){
        System.out.println(e.getMessage());
    }

    return -1;
}

public int realRemoval() throws EmptyBagException {

    if (counter == 0) {
        throw new EmptyBagException("There are no items in the bag!");
    } else {
        ...
    }
}

Then, I tried to test the exception by doing this:

@Rule
public ExpectedException thrown = ExpectedException.none(); 

@Test
public void testThree() {

    IBag myBag = new BasicBag();
    myBag.remove();
    thrown.expect(EmptyBagException.class);
    thrown.expectMessage("There are no items in the bag!");

}

Unfortunately, this test failed and I got the message:

java.lang.AssertionError: Expected test to throw (an instance of sg.com.practice.adt.EmptyBagException and exception with message a string containing "There are no items in the bag!")

I am not sure why this is so...especially since my intended error message was indeed correctly printed to the console. Thanks in advance for the help!


Solution

  • It's because you don't actually throw the exception out of remove():

    public int remove() {
    
        try {
            this.realRemoval();
        } catch (EmptyBagException e){
            System.out.println(e.getMessage());
        }
    
        return -1;
    }
    

    In this case, the exception from realRemoval() is caught and handled by your try...catch block. The exception is thrown by realRemoval() then caught by your handler, the message is printed, and that's it: The exception isn't rethrown, and -1 is returned instead.

    If you want it to rethrow the exception you'd have to do this instead:

    public int remove() throws EmptyBagException { // <-- declare throws
    
        try {
            this.realRemoval();
        } catch (EmptyBagException e){
            System.out.println(e.getMessage());
            throw e; // <-- rethrow
        }
    
        return -1;
    
    }
    

    Or just get rid of your output message and let it happen naturally:

    public int remove() throws EmptyBagException { // <-- declare throws
    
        this.realRemoval(); // <-- may throw
    
        return -1;
    
    }
    

    Also note that you'll want to set up thrown before calling remove() in your test function, as if remove() throws, then the test function will throw and won't actually get past that point to set up thrown.

    By the way, don't you mean to return the value of realRemoval() rather than -1?