### Question:
TransactionEnforcer { public <T> T executeAndReturn(Function<TimbuctooActions, TransactionStateAndResult<T>> action) { boolean success = false; TimbuctooActions timbuctooActions = timbuctooActionsFactory.create(afterSuccessTaskExecutor); try { TransactionStateAndResult<T> result = action.apply(timbuctooActions); if (result.wasCommitted()) { success = true; timbuctooActions.success(); } else { success = false; timbuctooActions.rollback(); } return result.getValue(); } catch (RuntimeException e) { success = false; timbuctooActions.rollback(); throw e; } finally { timbuctooActions.close(); if (success) { afterSuccessTaskExecutor.executeTasks(); } } } TransactionEnforcer(TimbuctooActions.TimbuctooActionsFactory timbuctooActionsFactory);   TransactionEnforcer(TimbuctooActions.TimbuctooActionsFactory timbuctooActionsFactory,
                      AfterSuccessTaskExecutor afterSuccessTaskExecutor); T executeAndReturn(Function<TimbuctooActions, TransactionStateAndResult<T>> action); void execute(Function<TimbuctooActions, TransactionState> action);  }### Answer:
@Test public void executeAndReturnExecutesTheAfterSuccessTaskExecutorAfterTheTransactionIsCommitted() { AfterSuccessTaskExecutor afterSuccessTaskExecutor = mock(AfterSuccessTaskExecutor.class); TimbuctooActions actions = mock(TimbuctooActions.class); TransactionEnforcer instance = TransactionEnforcerStubs.withAfterSuccessExecutorAndTimbuctooActions(afterSuccessTaskExecutor, actions); instance.executeAndReturn(timbuctooActions -> TransactionStateAndResult.commitAndReturn("")); InOrder inOrder = inOrder(actions, afterSuccessTaskExecutor); inOrder.verify(actions).success(); inOrder.verify(actions).close(); inOrder.verify(afterSuccessTaskExecutor).executeTasks(); }
@Test public void executeAndReturnDoesNotExecuteTheAfterSuccessTaskExecutorAfterTheTransactionIsRolledBack() { AfterSuccessTaskExecutor afterSuccessTaskExecutor = mock(AfterSuccessTaskExecutor.class); TimbuctooActions actions = mock(TimbuctooActions.class); TransactionEnforcer instance = TransactionEnforcerStubs .withAfterSuccessExecutorAndTimbuctooActions(afterSuccessTaskExecutor, actions); instance.executeAndReturn(timbuctooActions -> TransactionStateAndResult.rollbackAndReturn("")); verify(actions).rollback(); verifyZeroInteractions(afterSuccessTaskExecutor); }
@Test(expected = RuntimeException.class) public void executeAndReturnDoesNotExecuteTheAfterSuccessTaskExecutorWhenAnExceptionIsThrown() { AfterSuccessTaskExecutor afterSuccessTaskExecutor = mock(AfterSuccessTaskExecutor.class); TransactionEnforcer instance = TransactionEnforcerStubs.withAfterSuccessExecutor(afterSuccessTaskExecutor); try { instance.executeAndReturn(timbuctooActions -> { throw new RuntimeException(); }); } finally { verifyZeroInteractions(afterSuccessTaskExecutor); } }