Introduction to JUnit Framework

This post gives an introduction and overview of JUnit Framework.

1. What is JUnit?

JUnit is a simple, open source framework to write and run repeatable tests. It is an instance of the xUnit architecture for unit testing frameworks. JUnit features include:
  • Assertions for testing expected results
  • Test fixtures for sharing common test data
  • Test runners for running tests JUnit were originally written by Erich Gamma and Kent Beck.

2. Benefits of using JUnit

  1. JUnit is a testing framework that developers use for writing test cases while developing the software. They would write and run test cases for every function they write. So using this, you make sure that every single line of code will be tested.
  2. Every time you make a small or a big modification in the code (in any function), you can make sure that the function is performing well and has not broken any older functionality by executing all JUnit test cases in one go written for that function. So, you write a test case once, and go on using the test case, again and again, to make sure that- everytime software is modified it is working as expected!
  3. Using JUnit, you can easily create and most importantly manage a rich unit test case suite for the entire software.
  4. Any new member in the team can easily understand the test cases written and managed using JUnit and consequently contribute towards writing more test cases for developing a robust software.
  5. JUnit has become a standard for testing in Java programming language and is supported by almost all IDE’s e.g Netbeans, Eclipse etc. So, you work in any standardized IDE environment, you would find the support of JUnit in it.
  6. You can also integrate Ant with JUnit to allow executing test suites (all unit test cases) as part of the build process, capturing their output, and generating rich color enhanced reports. So, every time your build is ready, you can check the JUnit report which would instantly tell the complete unit testing status.

3. JUnit Simple Basic Template

The following templates are a good starting point. Copy/paste and edit these templates to suit your coding style.
SampleTest is a basic test template:
import static org.junit.Assert.*;
 
public class SampleTest {
 
    private java.util.List emptyList;
 
    /**
     * Sets up the test fixture. 
     * (Called before every test case method.)
     */
    @Before
    public void setUp() {
        emptyList = new java.util.ArrayList();
    }
 
    /**
     * Tears down the test fixture. 
     * (Called after every test case method.)
     */
    @After
    public void tearDown() {
        emptyList = null;
    }
    
    @Test
    public void testSomeBehavior() {
        assertEquals("Empty list should have 0 elements", 0, emptyList.size());
    }
 
    @Test(expected=IndexOutOfBoundsException.class)
    public void testForException() {
        Object o = emptyList.get(0);
    }
}

4. Fixture

In Junit4 there is no setup() or tearDown() method and instead of that we have @Before and @After annotations. By using @Before you can make any method as setup() and by using @After you can make any method as teardown(). If two or more tests must share the same test fixture state, then the tests may be trying to tell you that the classes under test have some undesirable dependencies.
Refactoring the design to further decouple the classes under test and eliminate code duplication is usually a better investment than setting up a shared test fixture.
You can add a @BeforeClass annotation to a method to be run before all the tests in a class, and a @AfterClass annotation to a method to be run after all the tests in a class. Here's an example:
import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;
 
public class SimpleTest {
 
    private Collection collection;
    
    @BeforeClass
    public static void oneTimeSetUp() {
        // one-time initialization code        
    }
 
    @AfterClass
    public static void oneTimeTearDown() {
        // one-time cleanup code
    }
 
    @Before
    public void setUp() {
        collection = new ArrayList();
    }
    
    @After
    public void tearDown() {
        collection.clear();
    }
 
    @Test
    public void testEmptyCollection() {
        assertTrue(collection.isEmpty());
    }
    
    @Test
    public void testOneItemCollection() {
        collection.add("itemA");
        assertEquals(1, collection.size());
    }
}
Given this test, the methods will execute in the following order:
oneTimeSetUp()
setUp()
testEmptyCollection()
tearDown()
setUp()
testOneItemCollection()
tearDown()
oneTimeTearDown()

4.1 Fixture Example

  • Add a field for each part of the fixture
  • Annotate a method with @org.junit.Before and initialize the variables in that method
  • Annotate a method with @org.junit.After to release any permanent resources you allocated in setUp,For example, to write several test cases that want to work with different combinations of 12 Swiss Francs, 14 Swiss Francs, and 28 US Dollars, first create a fixture:
public class MoneyTest {
    private Money f12CHF;
    private Money f14CHF;
    private Money f28USD;

    @Before public void setUp() {
        f12CHF= new Money(12, "CHF");
        f14CHF= new Money(14, "CHF");
        f28USD= new Money(28, "USD");
    }
}
Once you have the Fixture in place, you can write as many Test Cases as you’d like. Add as many test methods (annotated with @Test) as you’d like.

5. Create Simple JUnit Test Case

  1. Create a method and annotate a method with @org.junit.Test
  2. When you want to check a value, import org.junit.Assert.* statically, call assertTrue() and pass a boolean that is true if the test succeeds
  3. Run test using IDE or command line or if the project maven using mvn test command.
For example, to test that the sum of two Moneys with the same currency contains a value which is the sum of the values of the two Moneys, write:
@Test
public void simpleAdd() {
    Money m12CHF= new Money(12, "CHF");
    Money m14CHF= new Money(14, "CHF");
    Money expected= new Money(26, "CHF");
    Money result= m12CHF.add(m14CHF);
    assertTrue(expected.equals(result));
}
If you want to write a test similar to the one you have already written, write a Fixture instead.

6. Real World Example using JUnit Framework

Let's we have School Management System application and we want to write a sample test cases for School entity. In this example, we will see the sample JUnit test cases for School entity.
public class SchoolServiceImplTest { 
    private SchoolService schoolService;
       
    /**
     * This method initialize all domain objects required for test methods.
     */
    @Before
    public final void setUp() throws Exception {

        // Instantiates a School instance;
        school = new School();
        school.setName("smsSchool");
        school.setAddress("smsSchool");
        school.setContactNo("0778563251");
        school.setFaxNo("0778563251");
        school.setWebsite("virtusa.lk");
        school.setStartedDate(date);
        school.setModifiedTime(date);        
    }
  
    @Test
    public final void testAddSchool() throws Exception {
            School newSchool = schoolService.addSchool(school);
            assertNotNull("School Type object should not null ", newSchool);  
    }

   
    @Test
    public final void testUpdateSchool() {
            School newSchool = schoolService.addSchool(school);
            assertNotNull(newSchool);
            newSchool.setContactNo("0145785545");
            schoolService.updateSchool(newSchool);
    }

    @Test
    public final void testFindSchool() throws AkuraAppException {

            School newSchool = schoolService.addSchool(school);
            assertNotNull(newSchool);
            School findSchool = schoolService.findSchool(
                    newSchool.getSchoolId());
            assertNotNull("School Type object should not null ", findSchool);
    }

   
    @Test
    public final void testGetSchoolList() throws AkuraAppException {
            School newSchool = schoolService.addSchool(school);
            assertNotNull(newSchool);
            List<School> schoolList = schoolService.getSchoolList();
    }

   
    @After
    public final void teardown() throws SchoolNotFoundException {   
         schoolDao.delete(school);
    }
}

7. Expected Exceptions

How do you verify that code throws exceptions as expected?
Verifying that code completes normally is only part of programming. Making sure the code behaves as expected in exceptional situations is part of the craft of programming too. For example:
new ArrayList<Object>().get(0);
This code should throw an IndexOutOfBoundsException. The @Test annotation has an optional parameter expected that takes as values subclasses of Throwable. If we wanted to verify that ArrayList throws the correct exception, we would write:
@Test(expected= IndexOutOfBoundsException.class)
public void empty() {
    new ArrayList<Object>().get(0);
}

8. Conclusion

In this post, we have discussed what is JUnit framework and benefits of using JUnit Framework, basic template, fixture and an example. Learn JUnit framework on JUnit 4 Developers Guide.

Comments