### Question:
MethodDispatchStrategy extends AbstractDispatcher { public void dispatch(Notification notification) { try { sendNotification(notification); } catch (DispatchException e) { logger.error("Failed to dispatch notification: {}:", notification, e); instrumentFailedDispatch(notification.getMethod(), e); retryProcessor.retry(notification, e); } catch (DispatchUnsupportedByUserException | NoSuchProviderException e) { logger.error("Failed to dispatch notification: {}:", notification, e); instrumentFailedDispatch(notification.getMethod(), e); audit.log(notification, AuditEventState.ERROR, e); } catch (RuntimeException e) { logger.error("Failed unexpectedly during dispatch of notification {}:", notification, e); instrumentFailedDispatch(notification.getMethod(), e); audit.log(notification, AuditEventState.FAILED, e); } } MethodDispatchStrategy(NotificationAuditor audit, RetryProcessor retryProcessor, RetryManager retryManager, NotificationProviderRegistry providerRegistry); void dispatch(Notification notification);  }### Answer:
@Test public void notificationShouldBeSent() throws Exception { Mockito.when(retryManager.hasExpired(notification)).thenReturn(false); Mockito.when(providerRegistry.getInstanceForProvider(Mockito.any())).thenReturn(provider); uut.dispatch(notification); Mockito.verify(provider).notifyCustomer(notification); Mockito.verify(audit).log(notification, AuditEventState.SENT); }
@Test public void dispatchExceptionShouldRetry() throws Exception { Exception exception = new DispatchException("message"); Mockito.when(retryManager.hasExpired(notification)).thenReturn(false); Mockito.when(providerRegistry.getInstanceForProvider(Mockito.any())).thenReturn(provider); Mockito.doThrow(exception).when(provider).notifyCustomer(notification); uut.dispatch(notification); Mockito.verify(retryProcessor).retry(notification, exception); assertEquals(1L, ((Counter) METRICS.getMetrics().get("notifications.dispatch.email.dispatchexception")).getCount()); }
@Test public void terminalDispatchExceptionShouldTransitionToError() throws Exception { Exception exception = new DispatchUnsupportedByUserException("message"); Mockito.when(retryManager.hasExpired(notification)).thenReturn(false); Mockito.when(providerRegistry.getInstanceForProvider(Mockito.any())).thenReturn(provider); Mockito.doThrow(exception).when(provider).notifyCustomer(notification); uut.dispatch(notification); Mockito.verify(audit).log(notification, AuditEventState.ERROR, exception); assertEquals(1L, ((Counter) METRICS.getMetrics().get("notifications.dispatch.email.dispatchunsupportedbyuserexception")).getCount()); }
@Test public void runtimeExceptionShouldTransitionToFailed() throws Exception { RuntimeException exception = new RuntimeException("message"); Mockito.when(retryManager.hasExpired(notification)).thenReturn(false); Mockito.when(providerRegistry.getInstanceForProvider(Mockito.any())).thenReturn(provider); Mockito.doThrow(exception).when(provider).notifyCustomer(notification); uut.dispatch(notification); Mockito.verify(audit).log(notification, AuditEventState.FAILED, exception); assertEquals(1L, ((Counter) METRICS.getMetrics().get("notifications.dispatch.email.runtimeexception")).getCount()); }
@Test public void noSuchProviderExceptionShouldTransitionToError() throws Exception { NoSuchProviderException exception = new NoSuchProviderException("message"); Mockito.when(retryManager.hasExpired(notification)).thenReturn(false); Mockito.when(providerRegistry.getInstanceForProvider(Mockito.any())).thenThrow(exception); uut.dispatch(notification); Mockito.verify(audit).log(notification, AuditEventState.ERROR, exception); assertEquals(1L, ((Counter) METRICS.getMetrics().get("notifications.dispatch.email.nosuchproviderexception")).getCount()); }