Unit testing with JUnit 4 ( Maven project with Junit 4)


Unit testing is an inexpensive and efficient way to produce error free code lines. Although there is a dedicated division in every organization who perform testing and do quality activity on production or staging environment , however it is developer's responsibility to verify the code bocks (function,class,etc) written by them before integration. 
Junit (main agenda of this article) is a handy framework for Java developer for writing unit test cases and verify that functions or class method are working fine. In many organization, it is termed as test driven development (TDD) or test driven methodology and assumed as must-have skills for software developers. 
What is Unit test case and unit testing : A Junit test is a method contained in a class which is only used for testing.It is the piece of code written by developer to verify that outcome of functions/methods of real code lines are as expected what the developer thinks it should do and the process of verifying the same is called unit testing. 
For example, consider a method that generate employee salary slip. Salary computation depends on various factors like HRA, allowance and bonus and these values are retrieved from multiple database tables and some details like employee details are retrieved via a web-service.Here we have various internal methods involved like retrieve salary component from databases table based n employee id (getSalaryComponentsFromDB(.....)) and execute a REST service (http://employeeservice.company.com?empid=<employee id>) to get employee details. Report generation will be failed, if either of the above method and service execution failed or returned wrong data.
Here comes the Junit framework and provide developer a way to execute both of these method and service separately as independent methods with all possible inputs and verify that output retrieved is same as expected outcome. If we can spot our problem in unit testing it can save our many frustrating hours invested in debugging and finding error from holistic view of program at later stage.
What version of Junit test framework we should use ?
Junit has went through very wide range of changes from 3.x to 4.x and provides many others advantage, so we will using Junit 4.x in this post or further. No body will be nostalgic about 3.x unless they have legacy code lines using java 4. For using junit 4.x , we need java 5 and further (remember annotation was introduced in java 5).
Lets consider few important points before writing our  first unit test using junit 4.x :
  1. We need to annotate unit test case method with the @org.junit.Test annotation. (Import org.junit.Test  and just use @Test )
  2. For using Junit 4 , we need to place following jar files in class path or in lib folder.
         junit.jar
         hamcrest-core.jar  
  3. We have annotations like @BeforeClass, @AfterClass .Please refer this post for complete list of annotations , it is heart of Junit 4.

Environment  set-up for writing Junit: 

Junit test case can be written inside any java project or as a separate project. For shake of simplicity we will create a separate java project.Here I am using eclipse IDE and maven plugin installed in it.
Maven plugin  may not be installed in your eclipse, first install maven plugin and proceed.For Netbeans users step followed are same. You can download following project from here.

Junit maven project in eclipse:

  1. Create a maven project (File ->New -> Project and search for maven wizard and select maven project).And just keep all values default and proceed, fill groupId as com.mycompany and artifact id as JunitMavenproject (you can choose any name however, artifact id will be your project name so better choose a appropriate name as per need)
    Note : If you do not find, maven wizard it means mavn plugin is not installed, first install it.
    If you have created project successfully, project structure will looks like :
  2. You might spot a difference from your project structure in mavan dependencies section. You might having only one jar "junit-3.8.1.jar".No worry, it is just a matter of one simple change in pom.xml.
    Open pom.xml, go to lat tab pom.xml. Find <groupId>junit</groupId> under dependencies and change version associated from <version>3.8.1</version> to <version>4.12</version>. Do save and close pom.xml. Now, you must see two jar files as shown above in Maven dependencies section.
    Note: If you do not find any entry with group id Junit , add following dependency in your pom.xml.
<pre class="prettyprint">
          <dependency>
                 <groupId>junit</groupId>
                <artifactId>junit</artifactId>
                <version>4.12</version>
                <scope>test</scope>
                </dependency>
</pre>
  1. Now we are ready to write our first sample unit test program.Create a java class "MathematicalOperation.java" under src/java/main and paste following sample code or download sample project from here.
package com.mycompany.JunitMavenproject;

public class MathematicalOperation {
 
 public int multiply(int x, int y) {
     if (x == 0 || y==0) {
       throw new IllegalArgumentException("Input should not be 0," +
         "result will be 0 always ");
     }
     return x * y;
   }
 
 public int addition(int x, int y) {
     if (x ==y ) {
       throw new IllegalArgumentException("X is equal to Y, " +
         "so better multiply");
     }
     return x + y;
   }
}
  1. Now we will write Junit test for checking these two methods mutiply and addition(I know addition and multiply are not doing some rocket science work, for a moment just assume it is doing and we have to verify it).Create a java class "TestMathematicalOperation.java" under src/java/test and paste following sample code or download sample project from here.
package com.mycompany.JunitMavenproject;

import static org.junit.Assert.assertEquals;

import org.junit.AfterClass;
import org.junit.BeforeClass;
import org.junit.Test;

public class TestMathematicalOperation {
 static MathematicalOperation mo = null; 
 @BeforeClass
 static public void dataSetup(){
  System.out.println("Before first test method execution");
  mo = new MathematicalOperation();
 }
 @AfterClass
 static public void cleanUp(){
  System.out.println("After last test method execution");
  mo = null;
 }
 
 @Test
 public void multiplicationTest() {
  assertEquals("10 x 3 must be 30", 
    30, mo.multiply(10, 3));
  System.out.println("Multiply Tested!!");
 }
 
 @Test
 public void additionTest() {
  assertEquals("12 + 23 must be 35",
    35, mo.addition(12, 23));
  System.out.println("Addition Tested!!");
 }
}
Lets walk through the above code lines:
  • we have declared two test methods annotated by @Test and two supporting methods annotated by @BeforeClass and @AfterClass. Method doSetup() is executed automatically only once before execution of the very first test method (annotated by @Test) and similarly cleanUp() is executed after last test method execution.So the sequence of these methods execution are, first the method annotated with @BeforeClass followed by all test methods annotated with @Test and finally method annotated with @AfterClass. 
  • By default the order in which test methods are executed is not fixed, it may vary run to run. However, order of execution can be controlled by annotating test class with following annotation - it will sort method name in lexicographic order ascending using @FixMethodOrder(MethodSorters.NAME_ASCENDING).Similarly, we have MethodSorters.DEFAULT (default ordering followed )and MethodSorters.JVM(Random order). 
  • In each of the test methods we have assert statement, it compares expected result with actual method (multiply() and addition()) execution output, if both are equals test successfully passed and reported, otherwise it will report error(java.lang.AssertionError) with message passed as first argument to assertEquals method.
  1. Now we will execute the Junit program(Right click on the project -> Run as -> Junit Test) and below is the sample output that appears in console:
    --------------------------------------------------------------------
      Before first test method execution
      Addition Tested!!
      Multiply Tested!!
      After last test method execution
    --------------------------------------------------------------------
    and a visual representation specifying test method execution statistics (Run, Errors and Failure) as shown in below diagram(In netbeans the visual representation may not appear):
    JUnit  test method execution statistics 
There are certain naming conventions which need to be followed while creating test class, if do not do we may trap in issue like "Maven does not find JUnit tests to run". Netbeans user can spot this problem or if we try to run junit from command line like "mvn test". I do not find this issue in eclipse, eclipse is smart enough to take care of this.
  • By default Maven uses the following naming conventions when looking for tests to run:
    Test*  -   Test as prefix of test class name
    *Test  -   Test as suffix of test class name
    *TestCase -TestCase as sufix 
  • We can  configure Maven Surefire Plugin to use another pattern for test classes.
Test suite: Suppose we have multiple number of test classes, we can combine all test class and form a test suite. When we execute that test suite, it's all test classes will be considered sequentially and all test methods are executed.Support we have TestMathematicalOperation and TestBinaryOpeartion are two test classes, we can combine these two and make a suit and we just execute this suite class. Below is the code lines for the same: all test methods of TestMathematicalOperation and TestBinaryOperation will be execued.
package com.mycompany.JunitMavenproject;

import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;


@RunWith(Suite.class)
@SuiteClasses({ TestMathematicalOperation.class,
 TestBinaryOpeartion.class })
public class TestSuite {

} 
In next post we will see revisit some advance concept of Junit and will create sample project without Maven.
Next: Junit advance concepts - Paramertrised class, Junit rule, Cateogry,Mocking

1 Comments

Previous Post Next Post