如何在Android中测试assert抛出异常

时间:2011-09-26 08:39:18

标签: android exception junit

有没有更优雅的方法在Android中执行断言抛出异常呢?

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

        }
}

这样的东西不起作用?!

    @Test(expected=ElementNotFoundException .class)

谢谢,Mark

5 个答案:

答案 0 :(得分:4)

您使用的是junit4测试跑步者吗?如果您正在运行junit3测试运行器,则@Test注释将不起作用。检查您正在使用的版本。

其次,在代码中检查异常的推荐方法是使用规则(在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);
}

您可以继续使用@Test(expected = IOException.class),但上面的优点是,如果在调用exception.expect之前抛出异常,则测试将失败。

答案 1 :(得分:3)

我做了一些与hopia's answer非常相似的事情并做了一些改进。我让它返回异常对象,以便您可以检查其消息或任何其他属性,并且我声明了Testable接口来替换Runnable,因为Runnable不允许您的代码受到测试抛出已检查的异常。

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;
}

以下是调用它的示例。

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());

答案 2 :(得分:2)

我就是这样做的。我创建了一个名为assertThrowsException的静态方法,它接受一个预期的异常类和一个包含被测试代码的Runnable作为参数。

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.");
            }
        }
    }
}

这是在测试类中使用特殊断言的示例代码(扩展AndroidTestCase或其衍生产品之一):

public void testShouldThrowInvalidParameterException() {

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

}

是的,有很多工作,但它比将junit4移植到android更好。

答案 3 :(得分:0)

使用junit3可能会有所帮助。

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.");
    }
}

答案 4 :(得分:0)

如果您使用的是Kotlin,则可以利用reified types来避免将Exception子类作为参数传递:

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]
    }
}