From eb05ee41d982e68776ff798b4216a7e95ac9c08b Mon Sep 17 00:00:00 2001 From: erik Date: Mon, 5 Jul 2010 19:56:10 +0000 Subject: [PATCH] --- .../support/persistence/package-info.java | 197 ++++++++++++++++++ 1 file changed, 197 insertions(+) diff --git a/test/enterprise/src/main/java/org/wamblee/support/persistence/package-info.java b/test/enterprise/src/main/java/org/wamblee/support/persistence/package-info.java index e30b0b32..d38be579 100644 --- a/test/enterprise/src/main/java/org/wamblee/support/persistence/package-info.java +++ b/test/enterprise/src/main/java/org/wamblee/support/persistence/package-info.java @@ -13,5 +13,202 @@ * See the License for the specific language governing permissions and * limitations under the License. */ +/** + *

+ * This package provides test library for database testing in general and JPA testing + * specifically. As part of this it provides a means to transparently start an inmemory + * database from a junit test or connect to an external database. Also, given a persistence + * unit it is easy to start testing it in a junit test with only a few lines of code. + *

+ * + *

+ * The main use cases are explained below: + *

+ * + * + *

+ * See the design overview for a an overview of the design. + *

+ * + * + *

Basic database testing, transparently connecting to a database

+ *
+ * Starting the database: + *
+ *      Database db = DatabaseBuilder.getDatabase();
+ *      DataSource dataSource = db.start();
+ * 
+ * If nothing is specified in the user's environment, an inmemory database is started (derby). + * Using the datasource is just standard JDBC now. + * Stopping the database + *
+ *      db.stop();
+ * 
+ * + * + *

Connecting to an external database

+ *
+ * + * Connecting to an external database can be done by requiring the 'external' capability on + * the database provider. + *
+ *      Database db = DatabaseBuilder.getDatabase(DatabaseProvider.CAPABILITY_EXTERNAL); 
+ * 
+ * This also requires a number of environment variables or system properties to be set, + * see {@link ExternalDatabase}. + * + * + * + *

Executing code within a JDBC transaction

+ *
+ *

+ * To execute code withing a JDBC transaction, use the {@link DatabaseUtils} and + * use the {@link DatabaseUtils#executeInTransaction(org.wamblee.support.persistence.DatabaseUtils.JdbcUnitOfWork)} + * method. + *

+ *
+ *       DatabaseUtils dbutils = new DatabaseUtils(dataSource);
+ *       boolean result = dbutils.executeInTransaction(
+ *           new JdbcUnitOfWork<Boolean>() {
+ *               @Override
+ *               public Boolean execute(Connection aConnection) throws Exception {
+ *                   ResultSet res = jpaTester.getDbUtils().executeQuery(
+ *                       aConnection, GROUP_QUERY, aGroup);
+ *                   return res.next();
+ *               }
+ *           });
+ * 
+ * {@link DatabaseUtils} also provides various other utility methods to work with JDBC queries. + * + * + *

Using DB Unit in your tests

+ *
+ * + *

To work with DBUnit, {@link DatabaseUtils#createDbTester(org.dbunit.dataset.filter.ITableFilterSimple)} + * must be used passing it in the tables to use in the form of a {@link org.dbunit.dataset.filter.ITableFilterSimple} + * object.

+ * + *
+ *      IDatabaseTester dbtester = dbutils.createDbTester(new ITableFilterSimple() {
+ *          public boolean accept(String aTableName) throws DataSetException {
+ *              return aTableName.startsWith("XYZ_");
+ *          }
+ *      });
+ * 
+ * + *

The reason for using a DatabaseUtils instead of DBUnit directly is that + * DatabseUtils will keep track of connections and close them when DatabaseUtils + * is closed

+ * + * + *

Basic JPA testing

+ *
+ *

+ * First step is to create a {@link PersistenceUnitDescription} that matches the persistence unit you + * want to test. + *

+ *

Second step is to make sure that all entities are listed explicitly in your + *

persistence.xml
. Currently, class path scanning appears to fail when + * run from junit. + * Specifying all entities explicitly is not necessarily a bad thing as it is also more efficient. + *

+ * + *

+ * Now create a JpaTester in your test code: + *

+ *
+ *      @Before
+ *      public void setUp() throws Exception {
+ * 
+ *          // First we create the JpaTester by telling us which persistence unit we
+ *          // are going to test
+ *          jpaTester = new JpaTester(new MyPersistenceUnit());
+ *          jpaTester.start();     
+ *      }
+ * 
+ * + *

+ * Then in test code execute some JPA code within a unit of work: + *

+ *
+ *      jpaTester.getJpaBuilder().execute(new JpaUnitOfWork() {
+ *          public Void execute(EntityManager aEm) {
+ *              MyEntity entity = new MyEntity("a", "b");
+ *              aEm.persist(entity);
+ *              return null;
+ *          }
+ *      });
+ * 
+ * + * + *

JPA testing combined with JDBC and DBUnit

+ *
+ *

The JPATester provides access to all required object. It is usually convenient to + * get them directly from the JPATester after initializing it: + *

+ *      builder = jpaTester.getJpaBuilder();
+ *      dbtester = jpaTester.getDbUtils().createDbTester(new MyTables());
+ *      dbutils = jpaTester.getDbUtils();
+ * 
+ * + * + *

Testing a service that requires a transaction

+ *
+ * + *

Using {@link TransactionProxyFactory} it is possible to create a proxy for a given + * service interface to provide the semantics of 'requires new' transaction semantics. + *

+ *      TransactionProxyFactory factory = new TransactionProxyFactory(
+ *           jpaTester.getJpaBuilder(), Service.class);
+ *      Service service = new ServiceImpl(factory.getTransactionScopedEntityManager()); 
+ *      Service proxy = factory.getProxy(service);
+ *      proxy.execute(...);
+ * 
+ * + *

+ * In the above example, the Service POJO requires an {@link EntityManager} in its + * constructor and it is passed a transaction scoped entitymanager from the factory. This entitymanager + * is in fact a so-called contextual reference. + * Next, the proxy is obtained from the factory. Invoking any method on it will make sure a new + * transaction is started and a new entity manager is created for the scope of that transaction. + *

+ * + * + *

design overview

+ *
+ * + *

Database transaparency

+ * + *

Testing using JDBC and DBUnit

+ * + *

JPA tester overview

+ * + * + * + */ package org.wamblee.support.persistence; +import static org.mockito.Mockito.*; + +import javax.persistence.EntityManager; + +import org.junit.Before; +import org.wamblee.support.persistence.JpaBuilder.JpaUnitOfWork; +import org.wamblee.support.persistence.TransactionProxyFactoryTestBase.Service; + + -- 2.31.1