1

我有一个StandardUncaughtExceptionHandler捕获任何以前没有被其他异常捕获的异常。在后台,我使用 GuavaEventBus进行错误处理。对于我的应用程序中抛出的每种类型的检查异常,我都会向总线注册一个事件处理程序来处理该特定异常类型。如果总线发布了一个它没有注册处理程序的异常,它会将该异常包装在一个DeadEvent对象中,并将死事件重新发送回总线。这StandardUncaughtExceptionHandler已注册为侦听DeadEvents,向我保证我将始终有办法检查未捕获的异常。

这是主要来源:

public class StandardUncaughtExceptionHandler implements UncaughtExceptionHandler {
    private LoggingService loggingService;

    // Getter and setter for logginService.

    @Override @Subscribe
    public void handleUncaughtException(DeadEvent deadEvent) {
        // Log it.
        StringBuilder logBuilder = new StringBuilder();

        if(deadEvent.getEvent() instanceof Throwable) {
            Throwable throwable = (Throwable)deadEvent.getEvent();

            logBuilder.append("An uncaught exception occurred: ");
            logBuilder.append(throwable.getMessage());
            logBuilder.append(" - Stack trace: ");
            logBuilder.append(throwable.getStackTrace());
        }
        else
            logBuilder.append("Something weird happened.");

        loggingService.error(logBuilder.toString());
    }
}

我对它的测试,检查以确保当我们给它一个Throwable它构造正确的日志消息时。

@Test
public void handleUncaughtExceptionLogsThrowableIfPresent() {
    // GIVEN
    StandardUncaughtExceptionHandler fixture =
        new StandardUncaughtExceptionHandler();
    LoggingService mockLoggingService = Mockito.mock(LoggingService.class);
    DeadEvent mockDeadEvent = Mockito.mock(DeadEvent.class);

    Mockito.doThrow(new RuntimeException("Logging-Throwable"))
        .when(mockLoggingService)
        .error(Mockito.contains("An uncaught exception occurred:"));
    Mockito.doThrow(new RuntimeException("Logging-Something-Else"))
        .when(mockLoggingService)
        .error(Mockito.contains("Something weird happened."));
    Mockito.doReturn(new Throwable()).when(mockDeadEvent).getEvent();

    try {
        // WHEN
        fixture.handleUncaughtException(mockDeadEvent);

        Assert.fail();
    } catch(RuntimeException rte) {
        // THEN
        Assert.assertTrue(rte.getMessage().contains("Logging-Throwable"));
    }
}

运行此测试时,我的 JUnit 控制台中出现以下错误:

java.lang.NullPointerException
    at com.myapp.StandardUncaughtExceptionHandlerTest.handleUncaughtExceptionLogsThrowableIfPresent(StandardUncaughtExceptionHandlerTest.java:63)
    ... rest of stack trace omitted for brevity, it's huge

关于 Mockito 为什么会导致 NPE 的任何想法?我已经检查并重新检查,我相信我已经正确设置了我的模拟。提前致谢。

4

1 回答 1

3

Mockito 不是这里的问题。

我相信 NPE 在您的测试的以下行中报告:

Assert.assertTrue(rte.getMessage().contains("Logging-Throwable"));

因为rte.getMessage()返回null。不幸的是,由于try-catch单元测试中的块,这个错误的真正来源对你来说是隐藏的。取消注释揭示了真正的问题:try-catchhandleUncaughtExceptionLogsThrowableIfPresent()以下行中抛出了 NPE:

loggingService.error(logBuilder.toString());

因为loggingService从未在StandardUncaughtExceptionHandler类中初始化。此字段应在您的测试方法中使用模拟或任何其他有效方式进行初始化。

于 2013-02-11T21:29:44.703 回答