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).

3 comments:

Android Twitter Reader

1:30 PM , , 3 Comments

Following on from the RSS Reader, some time last year I was investigating using Twitter in some of my apps, so I put together this simple Twitter reader (it only reads tweets from a given user - it doesnt allow posting etc)




For the most it is the same as the RSS Reader in terms of laying out the Android Lists and the layout.xml, so I won't go over that, I will just go through the Twitter integration.

The first step is to retrieve all the tweets, for this I am using the very useful Twitter4J Java library that simply wraps the Twitter API with a Java API

Twitter twitter = new TwitterFactory().getInstance();
  List statuses = new ArrayList();
     try {
   statuses = twitter.getUserTimeline(screenName);
  } catch (TwitterException e) {
   Log.e("Twitter", "Error logging in to Twitter");
   Log.e("Twitter", e.getMessage());
  }


Once you have the list of latest tweets, I convert them in to JSON so my listAdapter can process them more easily:

ArrayList JOBS = new ArrayList();
  try {
   if (statuses.size()>0){
    for (Status s : statuses){
     String avatar = "http://" + s.getUser().getProfileImageURL().getHost() + s.getUser().getProfileImageURL().getPath();
     JSONObject object = new JSONObject();
     object.put("tweet", s.getText());
     String timePosted = Utility.getDateDifference(s.getCreatedAt());
     object.put("tweetDate", timePosted);
     object.put("author", s.getUser().getName());
     object.put("avatar", avatar);
     object.put("userObj", s.getUser());
     object.put("tweetId", s.getId());
     
     JOBS.add(object); 
    }
   }else{
    JSONObject object = new JSONObject();
    object.put("tweet", "You have not logged in yet! Please log on to view latest tweets");
    object.put("author", "");
    JOBS.add(object);
   }

  } catch (JSONException e1) {
   Log.e("JSON", "There was an error creating the JSONObject", e1);
  }


And thats pretty much that! the listAdapter just pulls the information out of the JSON objects as per above and displays as necessary. The only other thing I will show is a little Date util class to make the date posted a little more fun:

public static String getDateDifference(Date thenDate){
        Calendar now = Calendar.getInstance();
        Calendar then = Calendar.getInstance();
        now.setTime(new Date());
        then.setTime(thenDate);

        
        // Get the represented date in milliseconds
        long nowMs = now.getTimeInMillis();
        long thenMs = then.getTimeInMillis();
        
        // Calculate difference in milliseconds
        long diff = nowMs - thenMs;
        
        // Calculate difference in seconds
        long diffMinutes = diff / (60 * 1000);
        long diffHours = diff / (60 * 60 * 1000);
        long diffDays = diff / (24 * 60 * 60 * 1000);

  if (diffMinutes<60){
   if (diffMinutes==1)
    return diffMinutes + " minute ago";
   else
    return diffMinutes + " minutes ago";
  } else if (diffHours<24){
   if (diffHours==1)
    return diffHours + " hour ago";
   else
    return diffHours + " hours ago";
  }else if (diffDays<30){
   if (diffDays==1)
    return diffDays + " day ago";
   else
    return diffDays + " days ago";
  }else {
   return "a long time ago..";
  }
 }

3 comments:

Android RSS Reader 2.0

12:55 PM , , 15 Comments

Well, its now 2013, and I have updated a version of this post - a long with a complete working application on GitHub - you can find that here it covers Android 3.0+ so includes fragments and parsing the RSS in an AsyncTask. Of course, you can still read this post and access the code for the pre-3.0 version!

Since posting a link to my simple RSS Reader for Android implemented using a custom SAX parser I have some questions regarding upgrading to handle images - I have previously posted on how to implement new tags in the feed that you want to handle (including nested tags) - but one question I received was regarding when images are just embedded in the text (e.g. not a specific image tag, but say as part of a description as HTML).

So, I have updated the code (uploaded, see the sidebar) - this time it parses the description text data to retrieve any Image links its pretty grim string manipulation, but it does the job!


As you can see, it now parses the image URL from the description and inserts it to the left of the feed item.
What did I change?

First I needed to change the Article class to parse the link. I updated the setDescription method to also check for IMAGE tags to parse, if any found then it would set the ImgLink member:

 public void setDescription(String description) {
  this.description = description;
  
  //parse description for any image or video links
  if (description.contains("<img ")){
   String img  = description.substring(description.indexOf("<img "));
   String cleanUp = img.substring(0, img.indexOf(">")+1);
   img = img.substring(img.indexOf("src=") + 5);
   int indexOf = img.indexOf("'");
   if (indexOf==-1){
    indexOf = img.indexOf("\"");
   }
   img = img.substring(0, indexOf);
   
   setImgLink(img);
   
   this.description = this.description.replace(cleanUp, "");
  }
 }



I then also had to update the RssListAdapter class - this needed the necessary action to pull down the link based on our parsed URL and then inflate the ImageView in our row:
         if (jsonImageText.get("imageLink") != null){
          String url = (String) jsonImageText.get("imageLink");
                URL feedImage= new URL(url);
             
             HttpURLConnection conn= (HttpURLConnection)feedImage.openConnection();
                InputStream is = conn.getInputStream();
                Bitmap img = BitmapFactory.decodeStream(is);
                imageView.setImageBitmap(img);
         }

15 comments: