Take the 2-minute tour ×
Code Review Stack Exchange is a question and answer site for peer programmer code reviews. It's 100% free, no registration required.

In JUnit 3, I cannot tell JUnit what type of exception is expected. In JUnit 4, the declaration @Test(expected=NullPointerException.class) does it.

But, unfortunately in Android development, I can use only JUnit 3. So I wrote this simple method:

public class TestingUtils {

    public static void assertExpectedException(
                           Class<? extends Exception> exceptionClass, Runnable runnable) {
        try {
            runnable.run();
            throw new AssertionFailedError(
                         "Expected exception: <" + exceptionClass.getName() + ">");
        } catch (Exception e) {
            if (!exceptionClass.equals(e.getClass())) {
                throw new AssertionFailedError(
                        "Expected exception: <" + exceptionClass.getName() + "> " +
                        "but was: <" + e.getClass().getName() + ">"
                );
            }
        }
    }
}

Using:

public void testConstructorThrowsExceptionIfArgumentIsNull() {
    TestingUtils.assertExpectedException(IllegalArgumentException.class, new Runnable() {
        @Override
        public void run() {
            new SomeTestedClass(null);
        }
    });
}
share|improve this question
2  
The message for the case if it is was not thrown should be clearer, including something like "Expected exception X, but was not thrown". –  Bobby Feb 7 at 10:12
    
@Bobby thank you :) –  leonideveloper Feb 7 at 10:25
2  
FYI, I have done something similar in JDOM and I use it like this. –  rolfl Feb 7 at 11:23

1 Answer 1

up vote 5 down vote accepted

I have been though this loop before. I chose to do things in a slightly different way to you, in that instead of creating a Runnable, I instead add a try/catch block to the actual test.

Each system has pros/cons, but the differences are really cosmetic. Using a Runnable does make the JUnit logic better contained in the utility code.... but makes calling the utility test code a little bit more complicated. I am not sure which one I prefer.

I have a suggestion regarding this line here:

if (!exceptionClass.equals(e.getClass())) { ....

It is useful to be able to expect a super-type of an exception. For example, you want to trap an SQLException when you run a query, or you want to trap an IOException when you do something on a Stream..... you have the code:

TestingUtils.assertExpectedException(SQLException.class, ....);

but, the actual exception may be com.ibm.db2.jdbc.xxx.PicnicException, which is a subclass of SQLException.

Using equals() to match the exceptions is a problem.... you should use:

if (!exceptionClass.isInstance(e)) {....

One other thing, which is android specific.....

I found a bug in the Android Dalvik implementation/SDK relating to this problem... you should be setting the 'cause' for your AssertionError so that it is logged correctly. Unfortunately, the bug (which is fixed in Jelly-Bean) makes this impossible.

If you are sure you will be testing on Jelly-Bean or newer (the bug was fixed a while ago), you should also be initializing the cause on your AssertionError:

            AssertionFailedError tothrow = new AssertionFailedError(
                    "Expected exception: <" + exceptionClass.getName() + "> " +
                    "but was: <" + e.getClass().getName() + ">"
            );
            tothrow.initCause(e);
            throw tothrow;
share|improve this answer

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.