8

My unit tests use Hibernate to connect to an in-memory HSQLDB database. I was hoping there would be a way to clear and recreate the database (the entire database including the schema and all the data) in JUnit's TestCase.setUp() method.

Jack Edmonds
  • 31,931
  • 18
  • 65
  • 77

5 Answers5

7

you can config your hibernate configuration file to force database to recreate your tables and schema every time.

<!-- Drop and re-create the database schema on startup -->
<property name="hbm2ddl.auto">create-drop</property>

hibernate.hbm2ddl.auto Automatically validates or exports schema DDL to the database when the SessionFactory is created. With create-drop, the database schema will be dropped when the SessionFactory is closed explicitly.

e.g. validate | update | create | create-drop

if you don't like to have this config in your real hibernate config, you can create one hibernate config for unit testing purpose.

mhshams
  • 16,384
  • 17
  • 55
  • 65
  • 7
    This only recreates it every run. This means that if you are running your tests from eclipse, many will fail that would pass if run alone. At least this is my experience. – Bill K May 14 '13 at 23:20
  • 1
    @BillK That's my experience as well. – Craig Otis Jun 03 '18 at 14:37
3

If you are using Spring, then you can use the @Transactional attribute on your unit test, and by default at the end of every unit test all persisted data will be automatically rolled back so you dont need to worry about dropping the tables every time.

I haa walked throug an example here http://automateddeveloper.blogspot.com/2011/05/hibernate-spring-testing-dao-layer-with.html

rhinds
  • 9,976
  • 13
  • 68
  • 111
2
hibernate.hbm2ddl.auto=create-drop

And bootstrap a new SessionFactory.

Bozho
  • 588,226
  • 146
  • 1,060
  • 1,140
1

From testing perspective, the best practice is to clear data after every single test. If you use create-drop, it will also drop the table schema. This causes an overhead of recreating the schema everytime.

Since you are using hsql, which provides a direct mechanism to truncate, it would be the best option in this case.


@After
public void clearDataFromDatabase() {
    //Start transaction, based on your transaction manager
    dao.executeNativeQuery("TRUNCATE SCHEMA PUBLIC AND COMMIT"); 
    //Commit transaction
}   
Sairam Krish
  • 10,158
  • 3
  • 55
  • 67
0

Be careful with wiping the world and starting over fresh each time. Soon, you will likely want to start with a "default" set of test data loaded in your system. Thus, what you really want is to revert to that base state before each test is ran. In this case, you want a Transaction which rollsback before each test run.

To accomplish this, you should annotate your JUnit class:

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations={"classpath:/path/to/spring-config.xml"})
@TransactionConfiguration(transactionManager="myTransactionManager", defaultRollback=true)
public class MyUnitTestClass {
...
}

And then annotate each of your test methods with @Transactional:

@Transactional
@Test
public void myTest() {
    ...
}
Brad Lee
  • 629
  • 7
  • 11
  • Whether author want it or not, proposed approach is narrowing scenarios which can be tested like this, for instance you can't have multithreaded test with parallel transactions and rollback in the end. – okutane Oct 30 '22 at 20:34