6

In a Java project I'm working on I've got the following setup for our unit tests:

  • I'm using Spring Test MVC, @RunWith(SpringJUnit4ClassRunner.class) and @WebAppConfiguration to run the unit tests, and I create a MockMvc instance using webAppContextSetup(webApplicationContext) to test the application.
  • I've got a Hibernate config to set up an in-memory HSQLDB, all tables are created based on the @Entity classes.
  • In the Hibernate config, I'm setting the hibernate.hbm2ddl.import_files property to load a file import.sql with SQL statements to populate the (in-memory) database.

Now, I've confirmed all these above work:

  • Tests can successfully insert/retrieve from the in-memory DB.
  • The SQL statements in the import.sql are executed, as various tests confirm.

Now the problem: Errors occurring with statements I add in import.sql don't seem to be reported anywhere, neither is any indication given that an error occurred at all. Instead, subsequent statements are simply not executed. (I've confirmed this through testing.)

Is there any way or place these errors are reported that I'm apparently unaware of? Is there an additional Hibernate property for this?

Excerpt from hibernate test config:

    <bean id="sessionFactory" name="mySessionFactory" class="org.springframework.orm.hibernate4.LocalSessionFactoryBean">
        <property name="dataSource" ref="myDataSource" />
        <property name="hibernateProperties">
            <props>
                <prop key="hibernate.archive.autodetection">class,hbm</prop>
                <prop key="hibernate.dialect">org.hibernate.dialect.HSQLDialect</prop>
                <prop key="hibernate.show_sql">true</prop>
                <prop key="hibernate.connection.driver_class">org.hsqldb.jdbcDriver</prop>
                <prop key="hibernate.connection.username">sa</prop>
                <prop key="hibernate.connection.password"></prop>
                <prop key="hibernate.connection.url">jdbc:hsqldb:mem:myschema</prop>
                <prop key="hibernate.hbm2ddl.auto">create</prop>
                <prop key="hibernate.hbm2ddl.import_files">configuration/test/import.sql</prop>
                <prop key="hibernate.hbm2ddl.import_files_sql_extractor">org.hibernate.tool.hbm2ddl.MultipleLinesSqlCommandExtractor</prop>
                <!-- when using type="yes_no" for booleans, the line below allow booleans in HQL expressions: -->
                <prop key="hibernate.query.substitutions">true 'Y', false 'N'</prop>
            </props>
        </property>
    </bean>

3 Answers3

1

Not really an answer to your question, but alternative way to handle test DB population.

There is a XML namespace in Spring called jdbc that allows you to prepopulate your database with initial data during Spring context startup. Also it reports errors in your SQLs just fine:

<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
   xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
   xmlns:jdbc="http://www.springframework.org/schema/jdbc"
   xsi:schemaLocation="
       http://www.springframework.org/schema/beans
       http://www.springframework.org/schema/beans/spring-beans.xsd
       http://www.springframework.org/schema/jdbc
       http://www.springframework.org/schema/jdbc/spring-jdbc.xsd">

    <jdbc:initialize-database data-source="dataSource">
        <jdbc:script location="org/mytestproject/schema-drop-hsqldb.sql" />
        <jdbc:script location="org/mytestproject/schema-hsqldb.sql" />
        <jdbc:script location="org/mytestproject/data-hsqldb.sql" />
    </jdbc:initialize-database>

    <bean id="dataSource" class="org.apache.commons.dbcp.BasicDataSource" destroy-method="close">
        <property name="driverClassName" value="${jdbc.driver}"/>
        <property name="url" value="${jdbc.url}"/>
        <property name="username" value="${jdbc.username}"/>
        <property name="password" value="${jdbc.password}"/>
        <property name="validationQuery" value="${jdbc.validationQuery}"/>
    </bean>
</beans>
hoaz
  • 9,883
  • 4
  • 42
  • 53
  • Thanks for offering this alternative. When I implement it an error occurs regarding the non-existence of a used table. Could it be that this method executes the import.sql prior to Hibernate auto-creating the tables? – Ricardo van den Broek Apr 20 '15 at 20:57
  • Yes, add depends on hibernate sessionFactory. In my sample Spring creates and drops tables directly in SQL – hoaz Apr 20 '15 at 21:03
  • Unfortunately I'm stuck with having to use Hibernate's auto-creating here... Thanks anyways though, any further suggestions are welcome! – Ricardo van den Broek Apr 20 '15 at 23:05
  • have you tried `depends-on='sessionFactory'` in `initialize-database` bean? – hoaz Apr 21 '15 at 02:26
  • I'm sorry, I misread your comment! I'm being told (by my IDE and when I run it) that that's not a valid attribute for the `initialize-database` tag. Did I add it in the wrong spot? – Ricardo van den Broek Apr 21 '15 at 11:34
  • Oh you are right, I thought it should be there. Disregard my last comment – hoaz Apr 21 '15 at 12:45
1

I wasn't able to get exceptions to log, like @Julien Kroneg suggested.

But I was able to put a breakpoint in the catch block of the method org.hibernate.tool.hbm2ddl.SchemaExport#importScript where trimmedSql represents each SQL statement as it's being applied:

catch ( Exception e ) {
    if (haltOnError) {
        throw new ImportScriptException( "Error during statement execution (file: '"
                + namedReader.getName() + "'): " + trimmedSql, e );
    }
    exceptions.add(e);
    LOG.unsuccessful(trimmedSql);
    LOG.error(e.getMessage());
}

It may be enough, given how init scripts are static and not really business data, once you get them to work, they hopefully keep working.

DailyFrankPeter
  • 382
  • 1
  • 13
0

You can activate the logging on class org.hibernate.tool.hbm2ddl.SchemaExport with level TRACE.

Some errors are logged at DEBUG level (e.g. file not found):

10:29:21,039 DEBUG SchemaExport:353 - Import file not found: ../myFile.sql
Julien Kronegg
  • 4,968
  • 1
  • 47
  • 60