@Test
  public void whenPrepared() {
    AbstractTransaction tx = spy(new AbstractTransactionImpl());
    tx.prepare();

    tx.commit();
    verify(tx, times(1)).makeChangesPermanent();
  }
  @Test
  public void whenPrepareThrowsException_thenAbort() {
    AbstractTransaction tx = spy(new AbstractTransactionImpl());
    tx.start();

    RuntimeException expected = new RuntimeException();
    doThrow(expected).when(tx).doPrepare();

    try {
      tx.commit();
      fail();
    } catch (RuntimeException found) {
      assertSame(expected, found);
      assertIsAborted(tx);
    }
  }
  @Test
  public void whenDoCommitPreparedFails_thenAbort() {
    AbstractTransaction tx = spy(new AbstractTransactionImpl());
    tx.prepare();

    RuntimeException expected = new RuntimeException();
    doThrow(expected).when(tx).makeChangesPermanent();

    try {
      tx.commit();
      fail();
    } catch (Exception found) {
      assertSame(expected, found);
    }

    verify(tx, times(1)).doAbortPrepared();
    assertIsAborted(tx);
  }