Wednesday, January 4, 2012

JUnit 4.10 - Writing your first JUnit 4 test in a TDD Approach

In this article I will show you how to write your first JUnit 4 test.I will use Test Driven Development Approach (TDD from here onwards). This means I will first write an empty method to test. Then I will write the Test Class which will test this method. This of course means that the test will fail. Then once we know what we want from the test, we then refactor our actual method. This is exactly how it works in a TDD approach. We write the test first, then it fails, then we discover what needs to be refactored and we make the change in the class to test.

I will not use any IDE. A simple text editor like Notepad++ will suffice. This is in Windows environment.

  1. Download JUnit 4.10 source from here.

  2. Extract to C:\JUnit4.10.

  3. Add C:\JUnit4.10\junit-4.10.jar to CLASSPATH. Also make sure your JAVA_HOME variable is configured properly. Add your JAVA_HOME folder path to CLASSPATH as well since we will be compiling classes from command prompt.

  4. Now you are ready to write your first class.Since we are going to follow Test Driven Development, we will simply create a stub of the method we want to test.
    So go ahead and create a simple class called Calculator.java

    public class Calculator{

        public int add(int a, int b){
            return null;
        }

    }


    You notice that the method add, which we will test, returns null. This is a very simple test and you can figure out that it should return a + b. But this being TDD approach, we will not write this method. We actually want this method to fail. Now we are ready to write our Test Class.

  5. Go ahead and write the Test Class. We will call it CalculatorTest.java

    import static org.junit.Assert.*;
    import org.junit.Test;

    public class CalculatorTest{

        @Test
        public void testAdd()
        {
            Calculator calc = new Calculator(); //Setup object to Test
            int result = calc.add(2,8); //Call the method to Test
            assertEquals(10, result, 0); //Verify        
        }

    }


    The first thing to note is that I have annotated the method testAdd() with @Test. This is significant. The test suite will specifically look for methods with @Test in order to test it. Also note that test methods are void and the convention is to write testXX() where 'XX' is the name of the method to test.

    In any test method, you will first instantiate (by creating a new object in our case or use DI) the object to test. You would then set all the defaults of the object. In our case, there isn't any. This is the setup portion. You setup the object to test. Next you will call the method to test which may or may not return something. In our case it does. If it does not return, you can simply verify that the method has been called and that there is no exception. Finally, you assert or verify that the outcome is what you expect.

  6. Compile both classes from the command prompt using javac Calculator.java and javac CalculatorTest.java. Both should compile.

  7. Run the test from the command prompt again using java org.junit.runner.JUnitCore CalculatorTest


  8. You will get a Test Failed Error
    .

  9. Now you are ready to refactor!
    You know that your Calculator class needs to return the sum of the two passed-in integers by looking at the test. So you make that change.

    public class Calculator{

        public int add(int a, int b){
            return a+b;
        }

    }



  10. Repeat 6 and 7. You will now get a Test Passed message.


 

This is a very simple test. But think of a scenario when you have to test a very complex method. Even better think of a scenario where your method is tied up with resources(values) from your configuration file that you may not be able to access(acquire) in your local development environment. But you still need to write the method correctly before you can check-in the code. In such a scenario, you will mock out the object in the test class. This will ensure that your method is fully tested and what values of the mocked object you need from the configuration. At the very least, you will know how the method should actually work because tests should be informative.

I will be writing more on testing DAOs and Service layers (mocking) in the future. As usual, I appreciate your comments.