Unit testing Hibernate DAOs with dbUnit
For the longest time our unit test suite had lots of DAO unit tests that, in some cases, were using dbUnit already, but were connecting to an actual Oracle database while running. They were also automatically loading up the Spring DAO context (all of the DAOs) and all of the Hibernate mapping files for the whole project. This resulted in test cases that took roughly 20 seconds to run, which was way to long for a unit test to run.
In order to try to make them run faster, and be more self contained, we have modified the tests so that they no longer rely on the Spring context and loading all the hibernate mapping files. We have also moved to use HSQLDB, which HIbernate supports, an in-memory SQL database implemented in Java. Initial tests are positive, with many of the tests that previously took 15-20 seconds taking 3-4 seconds to run.
In order to do this, I had to switch from using a Spring-configured hibernate environment to a hand-configured hibernate environment that allows the test classes to define the hibernate mapping files to use. The important steps in doing this were to create a Hibernate Configuration object and define all of the HSQLDB/Hibernate related configuration for the tests and set up some automatic loading of test data via dbUnit.
Hibernate Configuration was pretty simple, and looks like this in my parent class setUp() method:
Configuration config = new Configuration().
setProperty("hibernate.dialect","org.hibernate.dialect.HSQLDialect").
setProperty("hibernate.connection.driver_class", "org.hsqldb.jdbcDriver").
setProperty("hibernate.connection.url","jdbc:hsqldb:mem:nwawebres").
setProperty("hibernate.connection.username", "sa").
setProperty("hibernate.connection.password", "").
setProperty("hibernate.connection.pool_size", "1").
setProperty("hibernate.connection.autocommit", "true").
setProperty("hibernate.current_session_context_class", "thread").
setProperty("hibernate.show_sql", "true").
setProperty("hibernate.cglib.use_reflection_optimizer", "false").
setProperty("hibernate.hbm2ddl.auto", "create-drop");This sets up Hibernate to use an in-memory HSQLDB that is re-initialized for every test run and has tables automatically created based on the specified Hibernate mapping files. In order to specify the hibernate mapping files, I created an abstract method that returns a list of strings, then I do the following:
Iterator i = getHibernateMappingFiles().iterator();
while(i.hasNext()) {
String file = (String) i.next();
System.out.println("Adding mapping file: " + file);
InputStream input = getClass().getResourceAsStream(file);
if(input == null) {
input = getClass().getClassLoader().getResourceAsStream(file);
}
config.addInputStream(input);
}After the hibernate mapping files are specified. I then have code that initialized the new database with base data based on the test class (See below for explanation of getDatabaseConnection() and getDatasetXmlLocation()):
_sessionFactory = config.buildSessionFactory();
_hibernateTemplate = new HibernateTemplate(_sessionFactory);
_hibernateTemplate.afterPropertiesSet();
Session session = _sessionFactory.openSession();
session.beginTransaction();
DatabaseConnection dbconn = getDatabaseConnection(session.connection());
try {
String xml = getDatasetXmlLocation();
InputStream input = getClass().getResourceAsStream(xml);
IDataSet dataSet = new XmlDataSet(input);
DatabaseOperation.INSERT.execute(dbconn, dataSet);
}
catch (DataSetException ex) {
System.out.println("Data not loaded " + ex.getClass().getName() + ", due to DataSetException");
System.out.println("Message: " + ex.getMessage());
// catch it. If there is no dataset avaible, exit graciously!
} catch (DatabaseUnitException e) {
System.out.println("Data not loaded" + e.getMessage() + ", due to Database Unit Exception");
// catch it. If there is no dataset avaible, exit graciously!
}
finally {
session.close();
}This method uses two other methods: getDatabaseConnection() and getDatasetXmlLocation():
protected String getDatasetXmlLocation() {
int idx = getClass().getName().lastIndexOf(".");
return getClass().getName().substring(idx + 1) + ".xml";
}And:
protected DatabaseConnection getDatabaseConnection(
Connection connection) {
DatabaseConnection dbconn = new DatabaseConnection(connection);
DatabaseConfig config = dbconn.getConfig();
config.setProperty(DatabaseConfig.PROPERTY_DATATYPE_FACTORY, new HsqldbDataTypeFactory());
return dbconn;
}This method can be used by child classes to get a database connection for verifying data in the database via dbUnit, like so:
QueryDataSet ds = new QueryDataSet(conn);
ds.addTable("CATALOG", "SELECT * FROM CATALOG WHERE id = " + catagoryId);
ITable table = ds.getTable("CATALOG");
...
Number id = (Number) table.getValue(0, "ID");
assertEquals("Wrong id", id.longValue(), cat.getId());After most of this goes in a parent class, child test classes just need to implement get getHibernateMappingFiles() method and define a setUp() method that creates the test DAO class and injects the _hibernateTemplate member variable from the parent class into the DAO.
Skype 2.0 For Linux in OpenSuSE 10.3
I finally got around to trying out the new Skype 2.0 release for linux. I had tried the beta a few months ago with almost no luck, so I had kind of put it off for a while.
At first I tried the RPM that was packaged for OpenSuSE 10.3, but didn’t have any luck with it. I’m not sure if it was something I had done by using Smart and some online repositories to mess up my package configuration, but it kept complaining that some 32bit compat libraries for QT4 hadn’t been installed, even though I think they were.
Eventually I just made sure all the libqt4-*-32bit RPMS were installed (via Smart) and then used the dynamically linked tarball version of Skype (from their downloads page).
At first everything was going well except video, then I noticed in their readme that they point out that you need to have the most recent version of the gspcav drivers (webcam drivers for linux), which OpenSuSE 10.3 doesn’t have. I think the version available with the online repositories is something like gspcav 1.00.12 and you need version 1.00.20 (as of when I am writing this). This is the version that was release on 12 Dec 2007. Using the OpenSuSE Build Service I found a pre-compiled version of the gspcav-kmp-default package that matched the latest kernel for OpenSuSE 10.3, and after getting that installed video worked like a charm. I haven’t made a call that uses the video yet, but I was able to get it working in the Skype configuration test window, so I have pretty high hopes.