Saturday, January 28, 2012

Mockito is just awesomeness

Last week I ventured into making some enhancements into a project that is completely unknown to me. I see unit tests as my writ of passage before I can checkin any code into a project new to me --not to say I should ever checkin code without tests, but I think you all know what I mean.

Writing tests for an unknown code is either difficult or tiresome; difficult, if I decide to understand large chucks of the project before writing a lick of code; tiresome, if I chose to only understand the module that I am changing and just mock the rest of classes when unit testing.  In reality, It should be a bit of both.

In the past I made lots and lots of mock objects by making classes that implement a certain interface or try to instantiate a class with lots of dependency, when really, I only care about one or two methods in the class. It's a tiresome, verbose, and just plain an ugly thing to do for writing a unit test.

Fortunately, I came across Mockito with allows you to mock and stub classes effortlessly.

Take the StatsManager class that has a genderCount() method.

public class StatsManager { 


    private JDBCTemplate template;
  

    public long genderCount(Gender gender) {
       //perform some business logic 
       
       ...
    } 
    
    public void setJDBCTemplate(JDBCTemplate template) {
      this.template = template;
    }
    
... 


}


Say I want to make a change to the genderCount() method and I need an unit test to validate my change.

Before Mockito, I would need to instantiate an instance of JDBCTemplate.  It happens that JDBCTemplate needs an javax.sql.DataSource instance to work. I would then try to make a mock class of this interface, but then it turns out that javax.sql.DataSource has a dependency javax.sql.Connection so I have to mock that class and world goes round and round... but I never finishing mocking!

What is it that I really need in order to test this code? It's the logic in genderCount() that I want to test, and don't want to concern myself with all these other setup classes/interfaces. Infact, I know that queryAsList(String sql) is the only method called on the JDBCTemplate class in StatsManager.genderCount() . All I want is a certain List of results when genderCount() is called.

This is exactly what Mockito give me! Here is an example

public class StatsManagerTest {

@Test
public void testGenderCount() {
    

    StatsManager manager = new StatsManager();


    JDBCTemplate template = mock(JDBCTemplate.class)


    List results = new ArrayList();
    //initialize list.
    ...

    when(template.queryAsList(anyString())).thenReturns(results);

   
    long maleCount = template.genderCount(Gender.MALE);
    //Assert a bunch of stuff
    ...


    long femaleCount = template.genderCount(Gender.FEMALE);
    //Assert a bunch of stuff
    ...

}


}



The key thing to notice here is the  when() and thenReturns() pair. What this is doing is that when queryAsList() is called regardless of what string is passed as a parameter, return this fixed list of results.
That's it! My unit test is concise/readable, free from a bunch of setup code.   I can always setup a different list of results to test against in my unit test.

It makes writing unit tests fun versus a necessary evil.

Back from Java haitus

It's been a whole 10 months since I've written any sensible Java code. Been developing a LAMP stack (we'll not exactly; lighttpd instead of apache). Lots of PHP, Javascript/JQuery, HTML, CSS.  Let's just say I've been itching for the type-safety.

This coming up in the next couple of months: Hadoop, Hive, Cascading, Spring, Membase and maybe even some Scala and Akka!  Stay tuned...