26 julio 2011

Using embedded databases in unit tests

Two years ago, I wrote a long blog post -in Spanish- about Test Driven Development. One of the sections of that blog post was about testing code that depends on a database. In short, never use an external database for unit tests.

Using mock objects to simulate the database connection is impractical. A better option is to start and shutdown a embed database. For that matter pure Java SQL databases like HSQL DB are really lightweight, for example a unit test that reads resources from disk usually takes more time than one that uses HSQL in memory.

At the time of that blog post I wrote a small code snippet to start and shutdown HSQL. I used that code snippet many times, but never took the time to create a reusable library for it. Fortunately the Spring guys made it for me :)

Since Spring Jdbc 3 there is an interface to handle embed databases for testing.

If you use Maven, add the dependency to Spring Jdbc (you don't have to use the whole Spring framework if you don't want to) and to HSQLDB:

<dependency>
     <groupId>org.springframework</groupId>
     <artifactId>spring-jdbc</artifactId>
     <version>3.0.5.RELEASE</version>
     <scope>test</scope>
</dependency>
<dependency>
     <groupId>hsqldb</groupId>

     <artifactId>hsqldb</artifactId>
     <version>1.8.0.7</version>
     <scope>test</scope>
</dependency>

Start the embed database before your tests:


@BeforeClass
public static void setUpDatabase() {
     sharedDatabase = new EmbeddedDatabaseBuilder() 

                           .addScript("hsqldb-test-ddl.sql")
                           .build()
}

The EmbedDatabase implements DataSource, so you can pass it to your objects:

hibernateSessionFactory.openSession(sharedDatabase.getConnection());

Shutdown the database after the tests:

@AfterClass
public static void tearDownDatabase() {
    if (sharedDatabase != null) {
        sharedDatabase.shutdown();
    }
}


Usually starting the HSQL server is fast, so you can use @Before and @After (instead of @BeforeClass / @AfterClass).

That's all.

02 mayo 2011

Using Spring dependency injection without XML

This is my second post in English, which is not my first language, so if you find errors let me know :)
Having said that, let’s go with the blog post…

It’s difficult to define what the Spring Framework provides, because is not a framework but a collection of them. The included frameworks covers pretty much everything from dependency injection (DI) to the creation of web applications. All of them designed to work seamlessly with the DI framework, and in particular with the XML way of configuring DI.

By using dependency injection you don’t need to modify your model to use Spring: you depend only on the DI framework to get the root objects of your application. At “lower levels” you can use some abstractions provided by the Spring Framework like JdbcTemplate or JmsTemplate, but you can use them without the DI framework too: they are part of the “Spring framework collection”, but they can work as independent frameworks.

Sadly in my experience, it seems that most of the developers are not aware of that: a lot of projects are too coupled with the Spring XMLs (which is only one convenient way of configuring DI), to the point that there are also dependencies to the “application-context.xml” in the unit tests. This is really bad. Spring XML is easy to write, but is a pain to maintain: it lacks abstraction mechanisms, you can’t debug it, is difficult to refactor and to find where the things are.

An alternative is to use Google Guice for the dependency injection part: It contains a nice API to define instance dependencies in code. You can use it with other Spring things, but I never feel comfortable to do that, because I think that mixing both frameworks could be a little bit confusing.

Spring DI can be configured by code, but to do it you have to pass some barriers:

  • All the documentation refers to the XML configuration.
  • The API to do the configuration directly in Java is awful.

 

Understanding the Spring API

The base interface to get instances from the DI injection framework is BeanFactory. The “Bean” prefix is there for historical reasons, but not be confused by it: your object classes doesn’t need to comply with the JavaBeans specification.

But to use a BeanFactory instance you need to configure it in some way, that’s why exists other interface called BeanDefinitionRegistry. This interface defines methods to register bean definitions (instances of BeanDefinition) that indicates how to create an instance.

To summarize:

  • BeanFactory: provides bean instances by name (getBean)
  • BeanDefintionRegistry: associates bean names with bean definitions (registerBeanDefinition).
  • BeanDefinition: provides information on how to create an object instance.

    Design side note: To me Spring is unnecessary complex in this part. The BeanDefinition provides information but it doesn’t do the instantiation, it means that each BeanFactory has to do that work (see AbstractBeanFactory.doGetBean). I think that if Spring delegates the instantiation to the definition, a lot of things could be simplified and the API becomes easier to use directly from Java.

If you used Spring before, you probably heard the name “ApplicationContext”. This is because the usual ways to get an implementation of BeanFactory is by using a ClassPathXmlApplicationContext or a XmlWebApplicationContext. That classes also implements other interfaces (i.e. ApplicationContext) that allows to plug-in lifecycle observers or enumerate beans (I assume that those functionality is required by other more “advanced” features provided by the framework).

 

Creating a BeanFactory instance for testing purposes

Before explaining how to do that… I want to give you an advice:

If you need to pass a Spring “ApplicationContext” or a “BeanFactory” in a lot of tests, you need to review your design and/or the way that you are testing. Maybe you are putting direct dependencies with the Spring context when all you need is to pass the required instances directly or maybe you are instantiating too much just to create an unit test.

After that short advice, here are some small code examples:

You can define beans by code, sadly the API is really ugly: BeanDefinitionBuilder provides you with methods to define beans (Ey, Spring guys! A good internal DSL to do this will be nice in the next release of Spring):

final StaticApplicationContext context = new StaticApplicationContext();
final BeanDefinitionBuilder builder =
       
BeanDefinitionBuilder.genericBeanDefinition(MockDataSource.class);
context.registerBeanDefinition("dataSource", builder.getBeanDefinition());

new MyApplication(context).run(); // MyApplication(BeanFactory context)

Using StaticListableBeanFactory you can pass instances, instead of using bean definitions (really useful to do tests):

final StaticListableBeanFactory context = new StaticListableBeanFactory();
context.addBean("dataSource", new MockDataSource());

new MyApplication(context).run();

By using a GenericApplicationContext you can combine XML from different sources with beans defined in code, for example:

GenericApplicationContext context = new GenericApplicationContext();
XmlBeanDefinitionReader reader = new XmlBeanDefinitionReader(context);
// this xml define the contentManager bean
reader.loadBeanDefinitions(new ClassPathResource("spring-config.xml"));

context.registerBeanDefinition("dataSource",
        BeanDefinitionBuilder.genericBeanDefinition(MockDataSource.class)
                             .getBeanDefinition());
context.refresh();

// contentManager uses dataSource
System.out.println(context.getBean("contentManager"));

 

Ok that’s all for this time :)