JUnit Exception Handling
  Posted January 30, 2003    PermaLink    Comments (5)  

Gherhard Froehlich was wondering if there was a better way to do positive JUnit exception testing than something like this:

public void testAddService() {
    try {
        setUp();
        TRACER.trace("--- Testing addService() ---");
        ssgConnectorProvisioning.addService(serviceData);
        TRACER.trace("--- End of test ---", "\n");
    } catch (Exception e) {
        if(e instanceof SSGConnectorException) {
           TRACER.exception("Test OK, because Exception was controlled", e);
        } else {
           TRACER.exception(e);
           fail(e.getMessage());
        }
    }
}

There is, the thing to do is to take advantage of the fact that java will only use one exception block, and it will match the first one that is an assignable class of the exception, so you could do this...

public void testAddService() {
    try {
        setUp();
        TRACER.trace("--- Testing addService() ---");
        ssgConnectorProvisioning.addService(serviceData);
        TRACER.trace("--- End of test ---", "\n");
    } catch (SSGConnectorException sce) {
        TRACER.exception("Test OK, because Exception was controlled", e);
    } catch (Exception e) {
        TRACER.exception(e);
        fail(e.getMessage());
    }
}

Let's hope he get's this via a Moveable Type pingback. (I've wanted to see if I have it working or not).

Update: I was kind of myoptic when I looked at the post Gherhard had and realized it was missing something this morning. Charles Miller also noticed it last night: the test should fail if no exception is thrown. steve tried to trim it down to a single catch:

public void testAddService() throws Exception{
    try {
        TRACER.trace("--- Testing addService() ---");
        ssgConnectorProvisioning.addService(serviceData);
        TRACER.trace("--- End of test ---", "\n");
    } catch (SSGConnectorException sce) {
        TRACER.exception("Test OK, because Exception was controlled", e);
    }

fail("We expected a SSGConnectorException");
}


Except in this case the test will fail if the exception is throw! (a false failure). And this also assumes SSGConnectiorException is the only exception thrown. If your tests are written so that only one test is done per test method (a good practice IMHO) you could fix this by putting a return statement in the catch block or moving the fail inside of the try block. Otherwise (such as cases where the exception is just a set up for the real test) you will need two fail statements or catch statements or continue the test in the catch block.

Trackback URL
  TrackBack URL for this entry:
http://shemnon.com/cgi-bin/mt/mt-tb.cgi/74
 
Comment
 
Name:Charles Miller
Date:January 31, 2003 03:21 AM

Firstly, the test is missing a _vital_ element - as written the test will succeed if the method doesn't throw an exception at all. Directly after the method that is supposed to throw the exception, put a 'fail("expected SSGConnectorException");'

Secondly, I tend to prefer just declaring the test method as throwing Exception. That way you don't have to bother with the "catch (Exception e)" block: any exception thrown other than the one you expect will be thrown out of the test method, and cause the test to fail (testrunner will print the stacktrace of the offending exception.

Oh, and thirdly, JUnit calls setUp() automagically before every test (and tearDown()) afterwards, so I'm not sure what the manual call is doing there.

 
Comment
 
Name:steve
Date:January 31, 2003 05:11 AM

so the code would read:

public void testAddService() throws Exception{
try {
TRACER.trace("--- Testing addService() ---");
ssgConnectorProvisioning.addService(serviceData);
TRACER.trace("--- End of test ---", "\n");
} catch (SSGConnectorException sce) {
TRACER.exception("Test OK, because Exception was controlled", e);
}

fail("We expected a SSGConnectorException");
}

And if you need a case where the call is successful that's a separate test.

 
Comment
 
Name:Charles Miller
Date:January 31, 2003 04:00 PM

Actually, if I were to write that test my code would read exactly as follows:

public void testAddServiceThrowsException throws Exception {
try {
ssgConnectorProvisioning.addService(serviceData);
fail("Expected SSGConnectorException");
} catch (SSGConnectorException e) {
// expected result
}
}

Tracing inside a test is, I've found, something of a wasted effort. JUnit tells you when you're going into the test. If an exception is thrown, the stacktrace will tell you exactly what line it came from. If the test fails, you can put enough information in the assert() to explain where and why. So long as you pick good test names, and have good descriptions for your assert() statements, tracing just seems redundant.

 
Comment
 
Name:Mike Moran
Date:February 1, 2003 07:03 AM

A way I usually write these tests is:

TheException caught = null;
try {
// code which should throw TheException
}
catch (TheException e) {
caught = e;
}
assertTrue("Expected to catch an exception",
exception != null);

 
Comment
 
Name:Sylvain Wallez
Date:February 5, 2003 02:38 PM

What about a simple :

try {
// code which should throw TheException
}
catch (TheException e) {
return; // Test is successful
}
fail("Expected to catch an exception");

 
Post Comment
 

Thanks for signing in, . Now you can comment. (sign out)

(If you haven't left a comment here before, you may need to be approved by the site owner before your comment will appear. Until then, it won't appear on the entry. Thanks for waiting.)


Remember me?


Name:
Email Address:
URL: