SingleThreadJTAExecutor { void doOps(TXState txState, CancelCriterion cancelCriterion) { try { beforeCompletion.doOp(txState); } finally { afterCompletion.doOp(txState, cancelCriterion); } } SingleThreadJTAExecutor();  SingleThreadJTAExecutor(BeforeCompletion beforeCompletion,
      AfterCompletion afterCompletion); void executeBeforeCompletion(TXState txState, Executor executor,
      CancelCriterion cancelCriterion); void executeAfterCompletionCommit(); void executeAfterCompletionRollback(); void cleanup(); boolean shouldDoCleanup();  }
@Test(expected = RuntimeException.class) public void doOpsInvokesAfterCompletionDoOpWhenBeforeCompletionThrows() { doThrow(RuntimeException.class).when(beforeCompletion).doOp(txState); singleThreadJTAExecutor.doOps(txState, cancelCriterion); verify(afterCompletion, times(1)).doOp(eq(txState), eq(cancelCriterion)); }