package org.testfun.jee; import org.apache.commons.lang.exception.ExceptionUtils; import org.junit.AfterClass; import org.junit.BeforeClass; import org.junit.Rule; import org.junit.Test; import org.junit.rules.ExpectedException; import org.junit.runner.RunWith; import org.testfun.jee.runner.PersistenceXml; import org.testfun.jee.runner.SingletonDataSource; import static org.hamcrest.CoreMatchers.*; import javax.persistence.EntityManager; import javax.persistence.PersistenceContext; import java.sql.*; import java.util.List; import static org.hamcrest.core.IsNot.not; import static org.junit.Assert.*; @RunWith(EjbWithMockitoRunner.class) public class EjbWithMockitoRunnerTransactionTest { private static boolean rowAdded; @PersistenceContext private EntityManager entityManager; @Rule public ExpectedException thrown = ExpectedException.none(); @BeforeClass public static void createTables() throws SQLException { dropTables(); try ( Connection connection = DriverManager.getConnection(PersistenceXml.getInstnace().getConnectionUrl()); Statement statement = connection.createStatement() ) { statement.execute("CREATE TABLE duplicates (id INTEGER GENERATED BY DEFAULT AS IDENTITY PRIMARY KEY, name VARCHAR(50) NOT NULL UNIQUE)"); } rowAdded = false; } @AfterClass public static void dropTables() throws SQLException { // Must rollback the connection used by the entity manager in order to avoid locks due to inserts done before (recall transactions are never committed). SingletonDataSource.getDataSource().getConnection().rollback(); try ( Connection connection = DriverManager.getConnection(PersistenceXml.getInstnace().getConnectionUrl()); Statement statement = connection.createStatement() ) { statement.execute("DROP TABLE IF EXISTS duplicates"); } } @Test public void test1() { firstAddRowNextVerify(); } @Test public void test2() { firstAddRowNextVerify(); } @Test public void dbThrowDuplicateKey() { entityManager.persist(new Duplicates("kuki")); try { entityManager.persist(new Duplicates("kuki")); } catch (Throwable t) { assertThat(ExceptionUtils.getRootCauseMessage(t), containsString("unique constraint or index violation")); } } @Test public void preUpdate() { Duplicates entity = new Duplicates("kuki"); entityManager.persist(entity); assertNull(entity.getDuplicateName()); entity.setName("puki"); entityManager.flush(); assertEquals(entity.getName(), entity.getDuplicateName()); } /** * This method is used for testing that a transaction is rolled back at the end of a test. * Because the rollback occurs after all @After methods are invoked, the test cannot be done using @After. * Also, there are no guarantees as for the order test methods are called. * This method solves the problem by performing "insert" on the first time it is called and "verify" on the second * time. */ private void firstAddRowNextVerify() { if (rowAdded) { // If a row was already added by a previous run, verify it was rolled back. List rows = entityManager.createQuery("FROM Duplicates AS dups").getResultList(); assertEquals(0, rows.size()); } else { // If no row was added so far (its the first call to this method) than add a row. Duplicates row = new Duplicates("kuki"); entityManager.persist(row); assertThat(row.getId(), not(0)); assertSame(row, entityManager.find(Duplicates.class, row.getId())); rowAdded = true; } } }