1 2 Previous Next 21 Replies Latest reply on Oct 5, 2010 9:21 AM by aslak

    Testing JPA 1.x with OpenEJB Embedded 3.1

    dan.j.allen

      I figured out how to test a JPA 1.x application using OpenJPA 1.2 and the OpenEJB Embedded 3.1 container adapter. The benefit is that it's fast, fast, fast!

       

      I haven't been able to get JPA 2.x to work since it's not supported in the release version of OpenEJB (3.1.2). I've heard, though, that support is just around the corner.

       

      The trickiest part of testing JPA is configurating a test DataSource. Fortunately, this is very easy to do in OpenEJB. Just create a jndi.properties file on the classpath (in src/test/resources if you are using Maven) and populate it with these properties:

       

      java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
      gameDatabase=new://Resource?type=DataSource
      gameDatabase.JdbcDriver=org.hsqldb.jdbcDriver
      gameDatabase.JdbcUrl=jdbc:hsqldb:mem:gamedb
      gameDatabase.JtaManaged=true
      java.naming.factory.initial=org.apache.openejb.client.LocalInitialContextFactory
      testDatabase=new://Resource?type=DataSource
      testDatabase.JdbcDriver=org.hsqldb.jdbcDriver
      testDatabase.JdbcUrl=jdbc:hsqldb:mem:testdb
      testDatabase.JtaManaged=true
      

       

      Of course you would change "testDatabase" and "testdb" to whatever you want to call your embedded database. HSQLDB is on the classpath by default when using OpenEJB. If you want to use another driver, just include the appropriate JAR on the classpath and update the JdbcDriver property.

       

      Eventually you'll be able to configure your JNDI properties in arquillian.xml (I hope)

       

      Next, you'll create a test-persistence.xml file on the classpath (in src/test/resources if you are using Maven) that initializes a database using this DataSource:

       

      <?xml version="1.0" encoding="UTF-8"?>
      <persistence version="2.0" xmlns="http://java.sun.com/xml/ns/persistence"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="
            http://java.sun.com/xml/ns/persistence
            http://java.sun.com/xml/ns/persistence/persistence_1_0.xsd">
         <persistence-unit name="test">
            <jta-data-source>testDatabase</jta-data-source>
            <properties>
               <!-- configures OpenJPA to generate the database schema automatically -->
               <property name="openjpa.jdbc.SynchronizeMappings" value="buildSchema(ForeignKeys=true)"/>
               <!-- print SQL being executed -->
               <property name="openjpa.Log" value="DefaultLevel=WARN, SQL=TRACE"/>
            </properties>
         </persistence-unit>
      </persistence>
      

       

      OpenJPA will fail to load if you forget to put one of the entity classes in the ShrinkWrap archive, so don't forget!

       

      Now you can simply inject an EntityManager into a session bean and use it. Since this is an EJB, all transactions are handled for you automatically.

       

      @Stateless
      @Local(PersistenceService.class)
      public class PersistenceServiceBean
      {
         @PersistenceContext
         private EntityManager em;
      
         public void seed()
         {
            em.persist(new Record("Sample record"));
         }
      
         public List<Record> selectAll()
         {
            return em.createQuery("select r from Record r").getResultList();
         }
      }
      

       

      Here's an example of an Arquillian test that invokes this service (in a real EJB environment!)

       

      @RunWith(Arquillian.class)
      public class PersistenceServiceTestCase
      {
         @Deployment
         public static Archive<?> createDeployment()
         {
            return ShrinkWrap.create(JavaArchive.class)
               .addClasses(Record.class, PersistenceService.class, PersistenceServiceBean.class)
               .addManifestResource("test-persistence.xml", "persistence.xml");
         }
      
         @EJB
         PersistenceService service;
      
         @Test
         public void queryShouldFindSeedRecord()
         {
            service.seed();
            List<Record> results = service.selectAll();
            assertEquals("Should have found one record", 1, results.size());
         }
      }
      

       

      Lately, we need to setup the dependencies needed to execute Arquillian. Here's an example of Maven profile that's active by default:

       

       <profile>
         <id>arq-openejb-embedded</id>
         <activation>
            <activeByDefault>true</activeByDefault>
         </activation>
         <dependencies>
            <dependency>
               <groupId>org.jboss.arquillian.container</groupId>
               <artifactId>arquillian-openejb-embedded-3.1</artifactId>
               <version>1.0.0.Alpha4</version>
            </dependency>
            <dependency>
               <groupId>org.apache.openejb</groupId>
               <artifactId>openejb-core</artifactId>
               <version>3.1.2</version>
            </dependency>
            <dependency>
               <groupId>javax.inject</groupId>
               <artifactId>javax.inject</artifactId>
               <version>1</version>
            </dependency>
         </dependencies>
      </profile>
      

       

      If you are testing with other containers, you'll want to put the OpenEJB resources (jndi.properties and test-persistence.xml) in their own resource directory (e.g., src/test/resources-openejb-embedded) and include that as a resource directory in the profile. See the Arquillian showcase for examples of this configuration.

       

      Have fun testing those mappings!

        • 1. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
          aslak

          nice little embedded stack..

          • 2. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
            dan.j.allen

            Indeed! I believe it's pretty straightforward to swap in Hibernate as well. But what I really want to be able to do is test JPA 2

             

            Are we planning to allow JNDI properties to be set in arquillian.xml? I really hate these jndi.properties files on the classpath. They smell

            • 3. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
              aslak

              yes we are.. just have to decide design wise if it's a protocol(in Arquillian sense, not 100% since it can not be replaced by e.g. http).

               

              We need a common InitialContext creation point somewhere, so the same info can be used by e.g. AS_CLIENT enrichers to inject Remote EJBs.

               

              Last time I think we came to the conclusion that Configuration could become a generic Object factory backed by a 'resolvers/creator' chain.. e.g. config.create(InitialContext.class), but we never moved forward on the idea.

               

              German is back and redoing some of the configuration code to move forward on the multi container support. see if he comes up with any brilliant ideas on subject..

              • 4. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                dan.j.allen

                Configuring the test to use Hibernate instead of OpenJPA isn't much more work.

                 

                First, set the provider to the Hibernate EntityManager in test-persistence.xml and add the Hibernate vendor properties for schema generation and SQL logging:

                 

                <persistence-unit name="test">
                   <provider>org.hibernate.ejb.HibernatePersistence</provider>
                   <jta-data-source>testDatabase</jta-data-source>
                   <properties>
                      <property name="hibernate.hbm2ddl.auto" value="create-drop"/>
                      <property name="hibernate.show_sql" value="true"/>
                   </properties>
                </persistence-unit>
                

                 

                Then include the proper JARs on the classpath, excluding OpenJPA and adding Hibernate EntityManager:

                 

                <profile>
                   <id>arq-openejb-embedded</id>
                   <dependencies>
                      <dependency>
                         <groupId>org.jboss.arquillian.container</groupId>
                         <artifactId>arquillian-openejb-embedded-3.1</artifactId>
                         <version>1.0.0.Alpha4</version>
                      </dependency>
                      <dependency>
                         <groupId>org.apache.openejb</groupId>
                         <artifactId>openejb-core</artifactId>
                         <version>3.1.2</version>
                         <exclusions>
                           <exclusion>
                             <groupId>org.apache.openjpa</groupId>
                             <artifactId>openjpa</artifactId>
                           </exclusion>
                         </exclusions>
                      </dependency>
                      <dependency>
                         <groupId>javax.inject</groupId>
                         <artifactId>javax.inject</artifactId>
                         <version>1</version>
                      </dependency>
                      <dependency>
                        <groupId>org.hibernate</groupId>
                        <artifactId>hibernate-entitymanager</artifactId>
                        <version>3.4.0.GA</version>
                        <scope>test</scope>
                        <exclusions>
                          <exclusion>
                            <groupId>javax.persistence</groupId>
                            <artifactId>persistence-api</artifactId>
                          </exclusion>
                          <exclusion>
                            <groupId>javax.transaction</groupId>
                            <artifactId>jta</artifactId>
                          </exclusion>
                        </exclusions>
                      </dependency>
                      <dependency>
                        <groupId>org.slf4j</groupId>
                        <artifactId>slf4j-jdk14</artifactId>
                        <version>1.4.2</version>
                        <scope>test</scope>
                      </dependency>
                   </dependencies>
                </profile>
                

                 

                Now you're testing with Hibernate!

                 

                Again, I recommend that you use different test resource directories to keep each of the configurations from stepping on each other's toes.

                • 5. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                  aslak

                  Sweet.. add a EclipseLink profile as well, and you can test between the most used JPA impls..

                   

                  Meaning the user can swap betwen impls, and get the same feel as between containers.. am I insane or is the impl f¤#&ed..

                  • 6. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                    dan.j.allen

                    Yep, this is fantastic. For instance, you can demonstrate which JPA providers permit lazy loading after the persistence context has been closed (hint, hint EclipseLink).

                     

                    It's also a great way to experiment with flushing, such as when it occurs, and also the extended persistence context.

                    • 7. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                      dan.j.allen

                      To get EclipseLink activated, you first have to add the Maven repository:

                       

                      <repositories>
                         <repository>
                           <id>eclipselink-repo</id>
                           <name>EclipseLink Repository</name>
                           <url>
                              http://www.eclipse.org/downloads/download.php?r=1&nf=1&file=/rt/eclipselink/maven.repo
                           </url>
                         </repository>
                      </repositories>
                      

                       

                      Yes, the ampersands need to be escaped like that.

                       

                      You'll need to use the EclipseLink provider and properties in test-persistence.xml

                       

                      <persistence-unit name="test">
                         <provider>org.eclipse.persistence.jpa.PersistenceProvider</provider>
                         <jta-data-source>testDatabase</jta-data-source>
                         <properties>
                            <property name="eclipselink.target-database"
                               value="org.eclipse.persistence.platform.database.HSQLPlatform"/>
                            <property name="eclipselink.ddl-generation" value="drop-and-create-tables"/>
                            <property name="eclipselink.logging.level" value="FINE"/>
                         </properties>
                      </persistence-unit>
                      

                       

                      Then you just need these dependencies:

                       

                      <dependencies>
                         <dependency>
                            <groupId>org.jboss.arquillian.container</groupId>
                            <artifactId>arquillian-openejb-embedded-3.1</artifactId>
                         </dependency>
                         <dependency>
                            <groupId>org.apache.openejb</groupId>
                            <artifactId>openejb-core</artifactId>
                            <exclusions>
                              <exclusion>
                                <groupId>org.apache.openjpa</groupId>
                                <artifactId>openjpa</artifactId>
                              </exclusion>
                            </exclusions>
                         </dependency>
                         <dependency>
                            <groupId>javax.inject</groupId>
                            <artifactId>javax.inject</artifactId>
                            <version>1</version>
                         </dependency>
                         <dependency>
                            <groupId>org.eclipse.persistence</groupId>
                            <artifactId>eclipselink</artifactId>
                            <version>1.1.2</version>
                            <scope>test</scope>
                         </dependency>
                      </dependencies>
                      

                       

                      Now you can pit Open JPA, Hibernate and EclipseLink up against one another!

                      • 8. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                        dan.j.allen

                        I can't wait for a candidate release of Open EJB 3.2 so that we can test JPA 2 this way. I'd love to hear if someone can figure out how to get that working.

                        • 9. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                          dan.j.allen

                          Great. I wouldn't really mind it if the container configuration had an InitialContext sub-section. I see where you are saying that there could be more than one, where one is at the client-side and the other in the container. Hopefully we can find some place to stick it soon

                          • 10. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                            ljnelson

                            One of the neat things we've got going at my company is a (non-Arquillian for the moment) test suite that uses OpenEJB 3.1.3-SNAPSHOT, which does have JPA 2.0 support, and a JUnit parameterized test that cycles through all major JPA providers.  You'd be surprised--or perhaps not!--at how far apart they all are.

                             

                            The real-world rule of thumb seems to be: test spec adherence with EclipseLink, and test fragility with OpenJPA.  Hibernate seems to just be lenient and easygoing with everything, but sometimes burns you behind your back.

                             

                            I would love to see a Maven surefire fork, or perhaps a JUnit @Rule or something like that, that would fork a JVM with this stack for each JPA implementation.  Because each JPA implementation really wants to do bytecode surgery on the JPA entities, doing it like we have it at the moment--in VM, with all enhancements turned off--only lets you do some basic stuff.

                             

                            Anyhow, to try to make this relevant: OpenEJB in particular is a great little container.  I would love to see an Arquillian feature that ran a test case over various JPA implementations in a row.

                             

                            Best,

                            Laird

                            • 11. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                              lincolnthree

                              Guys, this is HUGE. I have been writing a lot of JTA/JPA/EJB tests for my personal projects and I've been HATING the slowness of booting up JBoss AS, running the test suite, etc. Even on Remote (which is significantly faster than managed of course.) Also the fact that you can't deploy tests while the application itself is deployed because apparently EJBs are still global between webapps, so you you get multiple EJB errors and such... which means you have to undeploy the app before you run your tests if you're using the same server instance...

                               

                              Of course you could set up a new server and run on another port, but that's a huge PITA.

                               

                              I want this!!!

                              • 12. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                                aslak

                                Ok, going a bit off topic here.. but..

                                 

                                Seeing this, and having heard 'complaints' about Arquillian being hard to setup, and looking at the next version where we will be moving some of the dependency resolution out of maven and over into a internal one..

                                 

                                We could expand that into some form of arquillian profiles. We could host predefined profiles on some site, community could contribute profile setups.. so all you have to do is add the remote profile to your arq config, and of you go. complete set up of multiple containers with multiple dependency sets etc..

                                 

                                e.g.

                                 

                                Users arquillian.xml

                                <arquillian>
                                <import>http://jboss.org/arquillian/profile/openjpa+openejb_1.0.xml</import>
                                </arquillan>
                                
                                

                                 

                                 

                                openjpa+openejb_1.0.xml

                                 

                                <arquillian>
                                     <openejb:container>
                                          <dependencies>
                                               <dependency>org.apache.openejb:openejb-core:3.1</dependency>
                                               <dependency>org.apache.openjpa:openjpa:1.0</dependency>
                                          </dependencies>
                                     </openejb:container>
                                <arquillian>
                                
                                • 13. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                                  lincolnthree

                                  No, I think that's a good idea. I do think that Arquillian is currently a little too hard to set up. I think that it should provide a default container if no others are specified (e.g.: OpenEJB, Weld, OpenJPA, etc) by default, then let folks override it with JBossAS Managed/Remote / other containers / etc...

                                   

                                  This way people can just include Arquillian in their POM, it works, then go from there.

                                  • 14. Re: Testing JPA 1.x with OpenEJB Embedded 3.1
                                    lincolnthree

                                    Also, I think it would help to provide stack POMs for Arquillian.


                                    For example:

                                     

                                    Simply including this dependency would pull in all of the necessary dependencies for that container type. People could still use this in profiles if they want the option, but it simplifies at least the POM.

                                     

                                    These profiles could also include default arquillian.xml files that reduce configuration as much as possible, though I think you do that to some extent already, it could be made a little more streamlined.

                                     

                                    --Lincoln

                                    
                                          <dependency>
                                             <groupId>org.jboss.arquillian</groupId>
                                             <artifactId>arquillian-openejb-embedded-3.1-stack</artifactId>
                                             <version>1.0.0.Alpha4</version>
                                          </dependency>
                                    1 2 Previous Next