poniedziałek, 29 grudnia 2014

TDD with Spring3 + Hibernate + Transactions

I found many people, including myself, struggling with creating test environment for web apps using Spring, Hibernate and Transactions. Sometimes there's a need to test your services in action without mock objects and so on. So how do you do that?

Here's main configuration class:

import java.util.Properties;
import org.hibernate.SessionFactory;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.jdbc.datasource.DriverManagerDataSource;
import org.springframework.orm.hibernate4.HibernateTransactionManager;
import org.springframework.orm.hibernate4.LocalSessionFactoryBuilder;
import org.springframework.transaction.annotation.EnableTransactionManagement;
/**
 *
 * @author MarcinG
 */
@Configuration
@EnableTransactionManagement
@ComponentScan(basePackages = {})
public class DataTestConfig {

    
    @Bean
    public SessionFactory sessionFactory() {
        LocalSessionFactoryBuilder builder
                = new LocalSessionFactoryBuilder(dataSource());

        builder.configure("hibernate-test.cfg.xml");

        return builder.buildSessionFactory();
    }

    private Properties getHibernateProperties() {
        Properties prop = new Properties();
        prop.put("hibernate.format_sql", "true");
        prop.put("hibernate.show_sql", "true");
        prop.put("hibernate.hbm2ddl.auto", "create-drop");
        prop.put("hibernate.dialect",
                "org.hibernate.dialect.HSQLDialect");
        return prop;
    }

    @Bean(name = "dataSource")
    public DriverManagerDataSource dataSource() {

        DriverManagerDataSource ds = new DriverManagerDataSource();
        ds.setDriverClassName("org.hsqldb.jdbcDriver");
        ds.setUrl("jdbc:hsqldb:mem:test_db");
        ds.setUsername("sa");
        return ds;
    }

    @Bean
    public HibernateTransactionManager transactionManager() {
        return new HibernateTransactionManager(sessionFactory());
    }
} 
In my case I'm using Gradle, so I have file "hibernate-test.cfg.xml" inside Resources dir. It looks like that:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE hibernate-configuration PUBLIC "-//Hibernate/Hibernate Configuration DTD 3.0//EN" "http://hibernate.sourceforge.net/hibernate-configuration-3.0.dtd">
<hibernate-configuration>
 <session-factory>
  <property name="hibernate.connection.pool_size">10</property>
  <property name="hibernate.connection.autocommit">true</property>
  <property name="hibernate.cache.provider_class">org.hibernate.cache.HashtableCacheProvider</property>
  <property name="hibernate.hbm2ddl.auto">create-drop</property><!-- creates the tables from the entites automatically -->
  <property name="show_sql">true</property>
  <property name="dialect">org.hibernate.dialect.HSQLDialect</property>
  <mapping resource="pl/com/marcing/test/hibernate/Test.hbm.xml"/>
 </session-factory>
</hibernate-configuration>

Now you create tests like this one:

/**
 *
 * @author Gensiub
 */
@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(classes = {DataTestConfig.class})
public class TestFieldInRaportService {
    @Autowired
    TestService testService;

    /* service tests */ 
}
That service has @Transactional annotation. It uses DAO and so on. Test env will have in memory database which will work like a normal one. You can test whether you can retrieve previously saved objects and so on (no need for normal database).

Cheers!

Brak komentarzy:

Publikowanie komentarza