Showing posts with label unit testing. Show all posts

Hibernate + Spring - Testing the DAO Layer with an In Memory Database

For some time I have been working on developing a Java web app using Spring MVC & Hibernate, and as many will have discovered, this throws up lots of questions with unit testing. To increase my coverage (and general test confidence) I decided to implement some tests around the DAO layer. Up untill now, the DB access had been mocked out, and whilst some purists will argue that these are strictly "Integration tests" rather than unit tests, I decided to go ahead with the.

As I didn't want to be messing around with going near my dev DB, or worrying about dropping my dev data everytime I run a test I decided to test the DAO layer using in memory DB (HSQL), so here's how its done:

First, I added the dependency to my POM so the HSQL JARs were downloaded:

        
            hsqldb
            hsqldb
            1.8.0.10
            jar
            test
        


Next, in my Persistence.xml I added a new Persistence Unit, that would point my tests to my in-mem DB

    
        
            
            
            
            
            
            
            
            
        
    


Important points to note here are that the database name can be anything you like (well, as long as you have the url jdbc:hsqldb:mem: ..). Also, the username must be "sa" and the password "". There is no manual install needed, or explicit DBs created, as long as you have the JAR in your project everything will be handled for you.

Next, I copied my regular applicationContext.xml to src/test/resources, as I needed to configure this to point to my new Persistence Unit defined (and new data source)



    
    
    
        
    
   
    
        
    
   
    
   
    
   
    
        
    



As you can see, I have updated my Entity Manager Factory Bean to be using my newly created Test Persistence unit - this means any time Spring is fired up using the context definition, it will be pointing to my in-mem DB - Now I have configured everything, I am ready to start testing.

I started by writing an abstract test class - I used this to define my common @Before method (I needed to setup a common "test" user to allow db updates to complete), but the important thing here is the annotations on the class

@RunWith(SpringJUnit4ClassRunner.class)
@ContextConfiguration(locations = {"classpath:spring/test-applicationContext.xml"})
@Transactional
public abstract class AbstractServiceTest {


These annotations tell the tests that they are running with the Spring junit runner, and to use my newly created test-applicationContext.xml. The @Transactional is neccesary so we know to roll back all data persisted during the tests at the end of each test (we dont want test data leaking in to other tests and potentially affecting the outcome).

Now its just a case of writing the tests, here is an example of a test:

public class AccountServiceDbTest extends AbstractServiceTest{
   
    @Autowired
    AccountService service;

    @Test
    public void testFindAllAccounts() {
        List accs = service.findAllAccounts();
        assertEquals("Check DB is empty first", 0, accs.size());
        Account a = new Account();
        a.setUserName("robb");
        a.setPassword("password");
        service.storeAccount(a);
        accs = service.findAllAccounts();
        assertEquals("check Account has been created", 1, accs.size());
    }

}


The test checks that nothing is in the DB, then persists the new account to the table (all in-memory) and then checks the size to make sure it has been created correctly. At the end of the test the transaction is rolled back, so this will always work!

Another interesting point, is as I have defined the Spring context in the Abstract class, my tests are all now Sprin-managed, which means I can simply use the @Autowired annotation to autowire other Spring classes such as Service classes (these have my DAOs etc in).

How Testing Improves Design

Recently in work we have been looking at our testing strategies for a web app we are currently working on. The application itself is a Spring MVC java web app, and there are several challenges that we have faced around things like how to best test the persistence layer, testing the UI, mocking HTTP requests to test the controller calls, but today I was looking at testing a Service class that was used by one of our controllers.

The first challenge (as I was going for a bottom-up approach, starting with the most granular methods to test) was what is the best way to private methods. A little bit of initial research showed many people suggesting using reflection to test private methods, however, having spoken to the team's "test architect" he expressed a dislike for this approach as it resulted in failures at runtime (read test run time during build/package with maven) as due to the nature of reflection, if the contract of the class changes this is not flagged up with compile errors in your IDE. His suggested approach was just to make the methods public.  Clearly a bad idea and goes against basic OO principles, so I decided to investigate further..


On further reading, I started seeing a few people making claims such as "When I have private methods in a class that is sufficiently complicated that I feel the need to test the private methods directly, that is a code smell" - and I thought on this for a while, and looked at the code that I was testing and agreed.

Whilst the test architect had been wrong to suggest making all the methods public, I think it's fairer to say that you should be able to fully unit test a class with confidence only using public methods, these after all are your entry points, or contracts with the rest of the application, and your private methods are just implementation details - As the poster above states, if the private methods are so complex that you feel you should test them, then your design is wrong!

We all know about Principle of Single Responsibility and all that, but due to the constraints under which the application is being delivered, the service class had lost its way and many of the large, cumbersome, private methods shouldn't really have been there at all and needed to be refactored in to other relevant objects, where they could be exposed as public methods in themselves (obviously also helping reuse).  This is a common problem and easy to slip in to, you start off creating a Service class to perform some function, and as you develop it, the scope widens and more and more functionality is needed for this task, so it is easy to think that this functionality should be included in the same class, it is after all core to what the class is trying to achieve. However, you need to take a step back, as in this case during the testing, and analyse the class, does the functionality really belong in the class? Is it directly and singley contributing to the goal of the class?

With a quick nip and tuck the daunting task of mountains of private methods had all but disappeared and as well as that I could leave happy that the code was cleaner and more maintainable for it!