Reputation:
I have a StandardUncaughtExceptionHandler
which catches any exceptions that haven't been previously caught by other exceptions. Under the hood, I'm using a Guava EventBus
for error handling. For each type of checked exception thrown in my app, I register an event handler with the bus to handle that specific exception type. If the bus posts an exception that it doesn't have a registered handler for, it wraps that exception in a DeadEvent
object, and reposts the dead event back to the bus. This StandardUncaughtExceptionHandler
is registered to listen for DeadEvent
s, guaranteeing me that I'll always have a way to check for uncaught exceptions.
Here's the main source:
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());
}
}
And my test for it, checking to make sure that when we give it a Throwable
that it constructs the correct log message.
@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"));
}
}
When I run this test, I get the following error in my JUnit console:
java.lang.NullPointerException
at com.myapp.StandardUncaughtExceptionHandlerTest.handleUncaughtExceptionLogsThrowableIfPresent(StandardUncaughtExceptionHandlerTest.java:63)
... rest of stack trace omitted for brevity, it's huge
Any ideas as to why Mockito is causing the NPEs? I've checked and rechecked and I believe I've set my mocks up correctly. Thanks in advance.
Upvotes: 1
Views: 500
Reputation: 4110
Mockito is not the issue here.
I believe the NPE is reported in the following line of your test:
Assert.assertTrue(rte.getMessage().contains("Logging-Throwable"));
because rte.getMessage()
returns null
. Unfortunately due to the try-catch
block in your unit test, the real origin of this error is hidden from you. Uncommenting try-catch
in handleUncaughtExceptionLogsThrowableIfPresent()
reveals the real issue: a NPE is thrown in the following line:
loggingService.error(logBuilder.toString());
because loggingService
is never initialized in the StandardUncaughtExceptionHandler
class. This field should be initialized in your test method with the mock or in any other valid way.
Upvotes: 3