37

我正在编写一些 JUnit 测试来验证是否MyCustomException引发了类型异常。但是,此异常多次包装在其他异常中,例如 InvocationTargetException,而 InvocationTargetException 又被包装在 RuntimeException 中。

确定 MyCustomException 是否以某种方式导致我实际捕获的异常的最佳方法是什么?我想做这样的事情(见下划线):


try {
    doSomethingPotentiallyExceptional();
    fail("Expected an exception.");
} catch (RuntimeException e) {
     if (!e.原由(MyCustomException.class)
        fail("Expected a different kind of exception.");
}

我想避免调用getCause()一些“层”深,以及类似的丑陋解决方法。有没有更好的方法?

(显然,Spring 有NestedRuntimeException.contains(Class),它可以满足我的要求 - 但我没有使用 Spring。)

关闭: 好的,我想真的没有绕过实用方法:-) 感谢所有回复的人!

4

9 回答 9

44

如果您使用的是Apache Commons Lang,那么您可以使用以下内容:

(1) 当原因应该是指定的类型时

if (ExceptionUtils.indexOfThrowable(exception, ExpectedException.class) != -1) {
    // exception is or has a cause of type ExpectedException.class
}

(2) 当原因应该是指定类型或其子类类型时

if (ExceptionUtils.indexOfType(exception, ExpectedException.class) != -1) {
    // exception is or has a cause of type ExpectedException.class or its subclass
}
于 2015-03-25T10:17:09.620 回答
33

为什么要避免getCause。当然,您可以为自己编写一个执行任务的方法,例如:

public static boolean isCause(
    Class<? extends Throwable> expected,
    Throwable exc
) {
   return expected.isInstance(exc) || (
       exc != null && isCause(expected, exc.getCause())
   );
}
于 2009-03-04T14:05:32.060 回答
6

我认为您别无选择,只能通过 getCause 层调用。如果您查看您提到的 Spring NestedRuntimeException 的源代码,那就是它的实现方式。

于 2009-03-04T13:59:54.477 回答
2

模仿是最真诚的奉承。 基于对源的快速检查,这正是 NestedRuntimeException 所做的:

/**
 * Check whether this exception contains an exception of the given type:
 * either it is of the given class itself or it contains a nested cause
 * of the given type.
 * @param exType the exception type to look for
 * @return whether there is a nested exception of the specified type
 */
public boolean contains(Class exType) {
    if (exType == null) {
        return false;
    }
    if (exType.isInstance(this)) {
        return true;
    }
    Throwable cause = getCause();
    if (cause == this) {
        return false;
    }
    if (cause instanceof NestedRuntimeException) {
        return ((NestedRuntimeException) cause).contains(exType);
    }
    else {
        while (cause != null) {
            if (exType.isInstance(cause)) {
                return true;
            }
            if (cause.getCause() == cause) {
                break;
            }
            cause = cause.getCause();
        }
        return false;
    }
}

警告:以上是 2009 年 3 月 4 日的代码,所以,如果你真的想知道 Spring 现在在做什么,你应该研究现在存在的代码(无论何时)。

于 2009-03-04T14:32:14.807 回答
1

好吧,我认为如果不调用getCause(). 如果您认为这样做很难实现一个实用程序类:

public class ExceptionUtils {
     public static boolean wasCausedBy(Throwable e, Class<? extends Throwable>) {
         // call getCause() until it returns null or finds the exception
     }
}
于 2009-03-04T14:06:13.933 回答
1

您可以使用番石榴做到这一点:

FluentIterable.from(Throwables.getCausalChain(e))
                        .filter(Predicates.instanceOf(ConstraintViolationException.class))
                        .first()
                        .isPresent();
于 2014-07-21T18:41:26.760 回答
1

基于 Patrick Boos 的回答:如果您使用 Apache Commons Lang 3,您可以检查:

indexOfThrowable :返回与异常链中指定类(完全)匹配的第一个 Throwable 的(从零开始的)索引。指定类的子类不匹配

if (ExceptionUtils.indexOfThrowable(e, clazz) != -1) {
    // your code
}

或者

indexOfType :返回与异常链中指定的类或子类匹配的第一个 Throwable 的(从零开始的)索引。指定类的子类匹配

if (ExceptionUtils.indexOfType(e, clazz) != -1) {
    // your code
}

Java 8 的多种类型的示例:

Class<? extends Throwable>[] classes = {...}
boolean match = Arrays.stream(classes)
            .anyMatch(clazz -> ExceptionUtils.indexOfType(e, clazz) != -1);
于 2017-07-18T20:28:03.873 回答
1

您可以使用ExceptionUtils.hasCause(ex, type).

于 2020-11-04T02:39:55.053 回答
0

如果感兴趣的异常绝对是“根本”原因,assertj则可以在另一个地方进行getRootCause检查,尽管从今天的源头来看,它似乎在其他答案中讨论了可能的无限循环问题。

于 2021-09-14T11:30:09.690 回答