开发者

How to test assert throws exception in Android

is there a more elegant way to do an assert throws exception in Android then this?

public void testGetNonExistingKey() {   
        try {
            alarm.getValue("NotExistingValue");
            fail( );
        } catch (ElementNotFoundException e) {

        }
}

Something like开发者_运维百科 this does not work?!

    @Test(expected=ElementNotFoundException .class)

Thanks, Mark


Are you using a junit4 test runner? The @Test annotation won't work if you're running a junit3 test runner. Check the version that you're using.

Secondly, the recommended way to check for exceptions in your code is to use a Rule (introduced in junit 4.7).

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

@Test
public void throwsIllegalArgumentExceptionIfIconIsNull() {
    // do something

    exception.expect(IllegalArgumentException.class);
    exception.expectMessage("Icon is null, not a file, or doesn't exist.");
    new DigitalAssetManager(null, null);
}

You can continue to use the @Test(expected=IOException.class), but the above has the advantage that if an exception is thrown before the exception.expect is called, then the test will fail.


I did something very similar to hopia's answer with a couple of improvements. I made it return the exception object so that you can check its message or any other properties, and I declared a Testable interface to replace Runnable because Runnable doesn't let your code under test throw checked exceptions.

public interface Testable {
    public void run() throws Exception;
}

public <T extends Exception> T assertThrows(
        final Class<T> expected, 
        final Testable codeUnderTest) throws Exception {
    T result = null;
    try {
        codeUnderTest.run();
        fail("Expecting exception but none was thrown.");
    } catch(final Exception actual) {
        if (expected.isInstance(actual)) {
            result = expected.cast(actual);
        }
        else {
            throw actual;
        }
    }
    return result;
}

Here's an example of calling it.

InvalidWordException ex = assertThrows(
    InvalidWordException.class,
    new Testable() {
        @Override
        public void run() throws Exception {
            model.makeWord("FORG", player2);
        }
    });

assertEquals(
        "message", 
        "FORG is not in the dictionary.", 
        ex.getMessage());


If you're using Kotlin, you can take advantage of reified types to avoid passing the Exception subclass as an argument:

inline fun <reified T : Exception> assertThrows(runnable: () -> Any?) {
    try {
        runnable.invoke()
    } catch (e: Throwable) {
        if (e is T) {
            return
        }
        Assert.fail("expected ${T::class.qualifiedName} but caught " +
            "${e::class.qualifiedName} instead")
    }
    Assert.fail("expected ${T::class.qualifiedName}")
}

@Test
fun exampleTest() {
    val a = arrayOf(1, 2, 3)
    assertThrows<IndexOutOfBoundsException> {
        a[5]
    }
}


This is how I do it. I create a static method called assertThrowsException that takes in as arguments an expected exception class and a Runnable which contains the code under test.

import junit.framework.Assert;

public SpecialAsserts {
    public void assertThrowsException(final Class<? extends Exception> expected, final Runnable codeUnderTest) {
        try {
            codeUnderTest.run();
            Assert.fail("Expecting exception but none was thrown.");
        } catch(final Throwable result) {
            if (!expected.isInstance(result)) {
                Assert.fail("Exception was thrown was unexpected.");
            }
        }
    }
}

This is the sample code to use the special assert in your test class (that extends AndroidTestCase or one of its derivatives):

public void testShouldThrowInvalidParameterException() {

    SpecialAsserts.assertThrowsException(InvalidParameterException.class, new Runnable() {
        public void run() {
            callFuncThatShouldThrow();
        }
    });

}

Yes, there's a lot of work, but it's better than porting junit4 to android.


With junit3 the following might help.

public static void assertThrows(Class<? extends Throwable> expected,
        Runnable runnable) {
    try {
        runnable.run();
    } catch (Throwable t) {
        if (!expected.isInstance(t)) {
            Assert.fail("Unexpected Throwable thrown.");
        }
        return;
    }
    Assert.fail("Expecting thrown Throwable but none thrown.");
}

public static void assertNoThrow(Runnable runnable) {
    try {
        runnable.run();
    } catch (Throwable t) {
        Assert.fail("Throwable was unexpectedly thrown.");
    }
}
0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜