(no commit message)
authorErik Brakkee <erik@brakkee.org>
Mon, 5 Jul 2010 19:56:10 +0000 (19:56 +0000)
committerErik Brakkee <erik@brakkee.org>
Mon, 5 Jul 2010 19:56:10 +0000 (19:56 +0000)
test/enterprise/src/main/java/org/wamblee/support/persistence/package-info.java

index e30b0b324eb18f55a3a75b61d85acb27c36310ee..d38be5796fed215c5341d165ce549af23a5d4bbd 100644 (file)
  * See the License for the specific language governing permissions and
  * limitations under the License.
  */ 
+/**
+ * <p>
+ * 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.
+ * </p> 
+ * 
+ * <p>
+ * The main use cases are explained below:
+ * </p> 
+ * <ul>
+ *   <li> <a href="#db-basic">Basic database testing, transparently connecting to a database</a>  
+ *   </li>
+ *   <li> <a href="#db-basic-external">Connecting to an external database</a>
+ *   </li>
+ *   <li> <a href="#db-utils">Executing code within a JDBC transaction</a>
+ *   </li>
+ *   <li> <a href="#db-unit">Using DB Unit in your tests</a>
+ *   </li>
+ *   <li> <a href="#db-jpa-basic">Basic JPA testing</a> 
+ *   </li>
+ *   <li> <a href="#db-jpa-plus-jdbc">JPA testing combined with JDBC and DBUnit</a>
+ *   </li>
+ *   <li> <a href="#db-jpa-services">Testing a service that requires a transaction</a>
+ *   </li>
+ * </ul>
+ * 
+ * <p>
+ *   See the <a href="#design-overview">design overview</a> for a an overview of the design.  
+ * </p>
+ * 
+ * <a name="db-basic">
+ *   <h2>Basic database testing, transparently connecting to a database</h2>
+ * </a>
+ * Starting the database: 
+ * <pre>
+ *      Database db = DatabaseBuilder.getDatabase();
+ *      DataSource dataSource = db.start();
+ * </pre>
+ * 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
+ * <pre>
+ *      db.stop();
+ * </pre>
+ * 
+ * <a name="db-basic-external">
+ *   <h2>Connecting to an external database</h2>
+ * </a>
+ * 
+ * Connecting to an external database can be done by requiring the 'external' capability on 
+ * the database provider. 
+ * <pre>
+ *      Database db = DatabaseBuilder.getDatabase(DatabaseProvider.CAPABILITY_EXTERNAL); 
+ * </pre>
+ * This also requires a number of environment variables or system properties to be set, 
+ * see {@link ExternalDatabase}. 
+ * 
+ * 
+ * <a name="db-utils">
+ *   <h2>Executing code within a JDBC transaction</h2>
+ * </a>
+ * <p>
+ *   To execute code withing a JDBC transaction, use the {@link DatabaseUtils} and 
+ *   use the {@link DatabaseUtils#executeInTransaction(org.wamblee.support.persistence.DatabaseUtils.JdbcUnitOfWork)}
+ *   method. 
+ * </p>
+ * <pre>
+ *       DatabaseUtils dbutils = new DatabaseUtils(dataSource);
+ *       boolean result = dbutils.executeInTransaction(
+ *           new JdbcUnitOfWork&lt;Boolean&gt;() {
+ *               &#064;Override
+ *               public Boolean execute(Connection aConnection) throws Exception {
+ *                   ResultSet res = jpaTester.getDbUtils().executeQuery(
+ *                       aConnection, GROUP_QUERY, aGroup);
+ *                   return res.next();
+ *               }
+ *           });
+ * </pre>
+ * {@link DatabaseUtils} also provides various other utility methods to work with JDBC queries. 
+ * 
+ * <a name="db-unit">
+ *   <h2>Using DB Unit in your tests</h2>
+ * </a>
+ * 
+ * <p>To work with <a href="http://dbunit.org">DBUnit</a>, {@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. </p>
+ * 
+ * <pre>
+ *      IDatabaseTester dbtester = dbutils.createDbTester(new ITableFilterSimple() {
+ *          public boolean accept(String aTableName) throws DataSetException {
+ *              return aTableName.startsWith("XYZ_");
+ *          }
+ *      });
+ * </pre>
+ * 
+ * <p>The reason for using a <code>DatabaseUtils</code> instead of DBUnit directly is that 
+ * <code>DatabseUtils</code> will keep track of connections and close them when <code>DatabaseUtils</code>
+ * is closed</p>
+ * 
+ * <a name="db-jpa-basic">
+ *   <h2>Basic JPA testing</h2>
+ * </a>
+ * <p>
+ *    First step is to create a {@link PersistenceUnitDescription} that matches the persistence unit you
+ *    want to test. 
+ * </p>
+ * <p>Second step is to make sure that all entities are listed explicitly in your
+ *    <pre>persistence.xml</pre>. 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. 
+ * </p>
+ * 
+ * <p>
+ *    Now create a <code>JpaTester</code> in your test code: 
+ * </p>
+ * <pre>
+ *      &#064;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();     
+ *      }
+ * </pre>
+ * 
+ * <p>
+ * Then in test code execute some JPA code within a unit of work: 
+ * </p>
+ * <pre>
+ *      jpaTester.getJpaBuilder().execute(new JpaUnitOfWork<Void>() {
+ *          public Void execute(EntityManager aEm) {
+ *              MyEntity entity = new MyEntity("a", "b");
+ *              aEm.persist(entity);
+ *              return null;
+ *          }
+ *      });
+ * </pre>
+ * 
+ * <a name="db-jpa-plus-jdbc">
+ *   <h2>JPA testing combined with JDBC and DBUnit</h2>
+ * </a>
+ * <p>The <code>JPATester</code> provides access to all required object. It is usually convenient to 
+ * get them directly from the <code>JPATester</code> after initializing it: 
+ * <pre>
+ *      builder = jpaTester.getJpaBuilder();
+ *      dbtester = jpaTester.getDbUtils().createDbTester(new MyTables());
+ *      dbutils = jpaTester.getDbUtils();
+ * </pre>
+ * 
+ * <a name="db-jpa-services">
+ *   <h2>Testing a service that requires a transaction</h2>
+ * </a>
+ * 
+ * <p>Using {@link TransactionProxyFactory} it is possible to create a proxy for a given
+ * service interface to provide the semantics of 'requires new' transaction semantics. 
+ * <pre>
+ *      TransactionProxyFactory<Service> factory = new TransactionProxyFactory<Service>(
+ *           jpaTester.getJpaBuilder(), Service.class);
+ *      Service service = new ServiceImpl(factory.getTransactionScopedEntityManager()); 
+ *      Service proxy = factory.getProxy(service);
+ *      proxy.execute(...);
+ * </pre>
+ * 
+ * <p>
+ * In the above example, the <code>Service</code> 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.
+ * </p> 
+ * 
+ * <a name="design-overview">
+ *   <h2>design overview</h2>
+ * </a>
+ * 
+ * <h3>Database transaparency</h3>
+ * 
+ * <h3>Testing using JDBC and DBUnit</h3> 
+ * 
+ * <h3>JPA tester overview</h3>
+ * 
+ * 
+ * 
+ */
 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;
+
+