+package org.wamblee.support.persistence;
+
+import javax.sql.DataSource;
+
+import org.dbunit.IDatabaseTester;
+
+/**
+ * This class is the entry point for JPA tests. Test code should construct a JpaTester in the
+ * <code>@Before</code> method and call {@link #start()} on it in that method. Also, test code should
+ * call {@link #stop()} on it in the <code>@After</code> method.
+ *
+ * This class is constructed with a description of the persistence unit to be tested. The principle is that
+ * an existing <code>persistence.xml</code> can be tested without change in unit test code.
+ *
+ * It then takes care of the following:
+ * <ul>
+ * <li> Creating an inmemory database for testing (default) or connecting to an external database.
+ * See {@link DatabaseBuilder} for more information on how a databse is obtained.
+ * </li>
+ * <li> Drop all database tables that are related to the persistence unit under test, including JPA provider
+ * specific tables.
+ * </li>
+ * <li> Creating a datasource for the database and make the datasource available through JNDI.
+ * </li>
+ * <li> Creating the entity manager factory for JPA and configuring it in such a way that schema creation
+ * happens. (Typically, schema creation will be disabled in the persistence.xml but this utility enables it
+ * for unit test).
+ * </li>
+ * <li> Creating a DBUnit database tester which is appropriately configured for the persistence unit under test.
+ * </li>
+ * </ul>
+ *
+ * The main entry point for all this functionality is the {@link PersistenceUnitDescription} which describes the
+ * persistence unit and must be provided at construction of the <code>JpaTester</code>
+ *
+ * NOTE: Persistence XML files should be explicitly configured with the classes that are part of the persistence unit
+ * since scanning of classes does not work correctly in a unit test environment. This is currently the only limitation.
+ */
+public class JpaTester {
+
+ private PersistenceUnitDescription persistenceUnit;
+ private Database db;
+ private DataSource dataSource;
+ private DatabaseUtils dbUtils;
+ private JpaBuilder jpaBuilder;
+ private IDatabaseTester dbTester;
+
+ /**
+ * Constructs the tester.
+ * @param aPersistenceUnit Persistence unit under test.
+ */
+ public JpaTester(PersistenceUnitDescription aPersistenceUnit) {
+ persistenceUnit = aPersistenceUnit;
+ }
+
+ /**
+ * Starts the tester. This must be called prior to running the test.
+ * @throws Exception
+ */
+ public void start() throws Exception {
+ db = DatabaseBuilder.getDatabase();
+ dataSource = db.start();
+
+ dbUtils = new DatabaseUtils(dataSource, persistenceUnit.getTables());
+ dbUtils.dropTables();
+ dbUtils.dropTables(JpaCustomizerBuilder.getCustomizer().getJpaTables());
+
+ jpaBuilder = new JpaBuilder(dataSource, persistenceUnit);
+ jpaBuilder.start();
+
+ // db tester should be created after Jpa builder because jpa builder
+ // creates the
+ // tables that the tester looks at when it is initialized.
+ dbTester = dbUtils.createDbTester();
+ }
+
+ /**
+ * Stops the tester. This must be called after the test.
+ */
+ public void stop() {
+ if (jpaBuilder != null) {
+ jpaBuilder.stop();
+ }
+ if (db != null) {
+ db.stop();
+ }
+ }
+
+ public Database getDb() {
+ return db;
+ }
+
+ public DataSource getDataSource() {
+ return dataSource;
+ }
+
+ public IDatabaseTester getDbTester() {
+ return dbTester;
+ }
+
+ public DatabaseUtils getDbUtils() {
+ return dbUtils;
+ }
+
+ public JpaBuilder getJpaBuilder() {
+ return jpaBuilder;
+ }
+
+ public PersistenceUnitDescription getPersistenceUnit() {
+ return persistenceUnit;
+ }
+
+}