Announcement Announcement Module
Collapse
No announcement yet.
Junit testing with Ant & HSQLDB in memory Page Title Module
Move Remove Collapse
X
Conversation Detail Module
Collapse
  • Filter
  • Time
  • Show
Clear All
new posts

  • Junit testing with Ant & HSQLDB in memory

    Does anyone use an in-memory HSQLDB database to test their business layer (facades, business delegates, etc)?

    Right now I test my Hibernate DAOs and business delegates, running Junit via Ant. I use Hibernate's SchemaExportTask to create the schema before running the tests. The test case itself loads a Spring application context, and tests the various DAOs and facades. I'm currently using a MySQL db.

    This works fine, but I'd like it to be faster and more elegant, and running it via HSQLDB in memory would be the ultimate way to do it. I could use a file-based instance of HSQLDB, but this wouldn't be any quicker/better than using MySQL.

    The problem is, I'm not sure how to keep an in-memory instance of HSQLDB around between Ant tasks. For example, sure I can run the SchemaExportTask, but naturally that's pointless for a DB that only exists in memory for the duration of that task!

    Is anyone else out there successfully doing this?

  • #2
    I could use a file-based instance of HSQLDB, but this wouldn't be any quicker/better than using MySQL.
    The file based mode executes in the application's JVM so should be quicker than MySQL over a network, however, different DBs have subtle (and not so subtle) differences, so I wouldn't rely on this technique alone.

    Also have a look at Spring's AbstractTransactionalSpringContextTests which may speed up your tests.

    Comment


    • #3
      Does anyone use an in-memory HSQLDB database to test their business layer (facades, business delegates, etc)?

      Right now I test my Hibernate DAOs and business delegates, running Junit via Ant. I use Hibernate's SchemaExportTask to create the schema before running the tests. The test case itself loads a Spring application context, and tests the various DAOs and facades. I'm currently using a MySQL db.
      We use HSqlDB over here for unit-testing. MySQL DB (and others) are used only within the acceptance tests. As far as I see in the code we derive all test-cases from within the same test case. (In this case HibernateTestCase).

      The application context is stored by a static parameter but guarded with the context location (we use diffrent context locations over here). If the context location changes the application context is reloaded.

      The db and the session are initialized using:

      Code:
              getSession().clear();
              getLocalSessionFactoryBean().createDatabaseSchema();

      To protect the test cases from each other (side effects if tear down fails!), the application context is also guarded by the actual test-case class. So potential side-effects due incomplete tear-downs are limited on a per test-case class level.

      On tear-down all tables effected tables get cleared (special implementation by all DAO test cases).

      The whole test-case is usally surounded by a programmatical transaction, so in case of failure there is usally nothing committed - except some few extense transaction scenarios when fiddeling with application transactions (using programmatic transactions).

      By recycling the context the tests are really fast to do. The whole persistance / domain layer test suite consists of around 1000 test-cases and run within a minute. Compared to the acceptance tests running for minutes, this is quite a relief.

      Our business objects are defined using totally abstract classes (interfaces in terms of java). So mostly the advanced Business services are tested in isolation utilizing jMock.

      We plan to switch to TestNG and the new Spring support for test cases, so maybe you should check both, too. We expect some improvements in terms of control and simplicity. (The test code was original written starting with a pre-release Spring version.)


      Cheers,

      Martin (Kersten)[/code]

      Comment


      • #4
        Originally posted by Martin Kersten
        The db and the session are initialized using:

        Code:
                getSession().clear();
                getLocalSessionFactoryBean().createDatabaseSchema();
        I found this idea interesting, so I tried implementing a base test class, as follows:

        Code:
        import net.sf.hibernate.Session;
        import org.springframework.orm.hibernate.HibernateTransactionManager;
        import org.springframework.orm.hibernate.LocalSessionFactoryBean;
        import org.springframework.orm.hibernate.SessionFactoryUtils;
        import org.springframework.test.AbstractDependencyInjectionSpringContextTests;
        
        public abstract class BaseTestCase
            extends AbstractDependencyInjectionSpringContextTests
        {
            protected void onSetUp() throws Exception
            {
                HibernateTransactionManager txMgr = (HibernateTransactionManager)
                    applicationContext.getBean("transactionManager");
        
                Session session = SessionFactoryUtils.getSession(txMgr.getSessionFactory(), true);
        
                if (session != null)
                {
                    session.clear();
                }
        
                LocalSessionFactoryBean sessionFactoryBean = (LocalSessionFactoryBean)
                    applicationContext.getBean("sessionFactory");
        
                sessionFactoryBean.createDatabaseSchema();
            }
        }
        The corresponding applicationContext.xml has the following relevant lines in it:

        Code:
        <bean id="sessionFactory" class="org.springframework.orm.hibernate.LocalSessionFactoryBean">
            <property name="dataSource">
                <ref local="dataSource"/>
            </property>
            <!-- some stuff ommitted for brevity-->
        </bean>
        <bean id="transactionManager" class="org.springframework.orm.hibernate.HibernateTransactionManager">
            <property name="sessionFactory"><ref local="sessionFactory"/></property>
        </bean>
        Here's a concrete test case:

        Code:
        public class TestStoreFacade extends BaseTestCase
        &#123;
            private StoreFacade storeFacade;
        
            protected void onSetUp&#40;&#41; throws Exception
            &#123;
                super.onSetUp&#40;&#41;;
                storeFacade = &#40;StoreFacade&#41; applicationContext.getBean&#40;"storeFacade"&#41;;
            &#125;
        
            public void testSomething&#40;&#41;
            &#123;
                Item item = storeFacade.createItem&#40;"foo"&#41;;
                assertNotNull&#40;item&#41;;
            &#125;
        
            protected String&#91;&#93; getConfigLocations&#40;&#41;
            &#123;
                return new String&#91;&#93; &#123;"applicationContext.xml"&#125;;
            &#125;
        &#125;

        In theory that should work, but for some reason I get a ClassCastException on this line of BaseTestCase:

        Code:
        LocalSessionFactoryBean sessionFactoryBean = &#40;LocalSessionFactoryBean&#41;
                    applicationContext.getBean&#40;"sessionFactory"&#41;;
        It claims that the object that I think is of type LocalSessionFactoryBean is in fact of type net.sf.hibernate.impl.SessionFactoryImpl. Yet, that's now how it is declared in the applicationContext.xml file.

        Does anyone know what is going on here, and how I can get an instance of LocalSessionFactoryBean?

        Comment


        • #5
          Use autowiring in testcase and create getter/setter methods

          Code:
              public void setLocalSessionFactoryBean(LocalSessionFactoryBean sfbean){
                  this.sfbean = sfbean;
              }
          
              public LocalSessionFactoryBean getLocalSessionFactoryBean() {
                  return sfbean;
              }

          Comment


          • #6
            or use the "&" character in the XML configuration to get the actual FactoryBean and not its product (see more info in the reference documentation).

            Comment


            • #7
              Works with Hibernate Schema export

              I am using an in-memory HSQLDB for unit-testing of HQL. Combined with a DBUnit dataset each unit test is rigged with a fresh db-instance. In the test setup I create with Hibernate Schemaexport the database with tables. Works perfectly. See http://www.cybersnippet.nl/blog/entr...with_in_memory for more info about the setup.

              Is a fresh dataset each test not better for you ??

              Comment

              Working...
              X