Tuesday, January 25, 2011

Junit Best Practices with detailed examples - Must for every Java Developer

This is second in our tutorial series of junit.
If you wish to retouch junit basics : http://codingbasics.blogspot.com/2011/01/junit-tutorial-1-junit-with-example.html
In this blog, we will touch up some very important best practices for junits.

Unit Test cases need to be independent:

Each unit test should be independent of all other tests.  A unit test should execute one specific behavior for a single method.
Validating behavior of multiple methods is problematic as such coupling can increase refactoring time and effort.

 Consider the following example:

void testAdd(){
     int val1 = myClass.add(1,2);
     int val2 = myclass.add(-1,-2);
     assertTrue (val1 - val2 == 0);
}

If the assertions fails in this case, it will be difficult to determine which invocation of add() caused the problem.

If you want to test a method for multiple behaviors then one test method must be written for each scenario.
This will make the unit test case focus on the particular behavior of the method with great clarity and maintainability.
Please see the self-explanatory following example in testing a method called divide()

public void testNegativeValues()
{
// This method is used to test for negative values scenario.
}

public void testDivideByZero()
{
// The name very well explains what is this test all about.
}

Lets see some more



When testing output of Collections(List, Set) test for Null and Emptiness
Methods returning collections should be tested for more conditions.

Test for NULL
Test for emptiness
Test for list not returning null ( if requirements allow )
Test for object are of same type, if your requirement is so ( applicable for Java 1.4 )


No java Conditional expressions/Decision Making in Unit Tests please !!!!!!!

No unit test case must not contain java conditional expressions to test some scenarios.
Use assertion to handle the same.

This is bad :

public void testMethod()
{
Student s1 = obj.Method();
if(s1!=null)
assertEquals("sachin", s1.getName());

}

This is much better :

public void testMethod()
{
Student s1 = obj.Method();
assertNotNull(s1);
assertEquals("sachin", s1.getName());


}

Another Example :

public void testMyAge()
{
int age = obj.MyAge(dob);
assertEquals(age, calculateAge(dob)); // bad practice
assertEquals(age, 30); // Best practice. Try to use constants in assertions.
}

Unit Testing Exceptions is equally important


Most of the developers who write JUnit will forget / fail to test the exceptions thrown from the methods.
Right exceptions thrown always convey it’s inherit information. Say you have a exception designed as below

class CarEngineException extends Exception
{
    int engineErrorCode;
    String message;


    public void runEngine() throws CarEngineException
    {


        if(someCondition1)
        {
                List l = someOtherProcess();
                if(l.isEmpty())
                {
                    CarEngineException ex = new CarEngineStartException();
                    ex.setMessage("some message for failure");
                    ex.setEngineErrorCode(1);
                }
                else if(l.size() == 1)
                {
                    CarEngineException ex = new CarEngineStartException();
                    ex.setMessage("some message for failure");
                    ex.setEngineErrorCode(1);
                }
         }
    }
}
In the above case, exceptions are vital part of the method’s response.
One should test the method’s exception, else you are not performing complete testing.


Always include a message to assertion
More the messages, less your debug time. Providing as many details as possbile is always good for debugging.
assertEquals("Error code should be 100", 100, e.getErrorCode() );


No comments:

Post a Comment

subversion video