Unit Testing with JUnit 4 in Java: Quick Introduction and Simple Samples

Unit testing is an important part of software development because it helps capture bugs before it moves on to QA or even customers. However, it’s not part of the end product therefore whatever you invest in unit testing will not yield any direct result but indirect result in better quality of your product. So at one side, you want to do it more for better quality; on the other side, you want to minimize it for less investment. It’s therefore a tricky trade off for best ROI. For more discussion, see here.

JUnit is a very popular framework for unit testing in Java and has been ported to other programming languages as well. I revisited JUnit with the latest JUnit 4 and found there are quite some changes from version 3.

Bothered by SLOW Web UI to manage vSphere? Want to manage ALL your VMware vCenters, AWS, Azure, Openstack, container behind a SINGLE pane of glass? Want to search, analyze, report, visualize VMs, hosts, networks, datastores, events as easily as Google the Web? Find out more about vSearch 3.0: the search engine for all your private and public clouds.

Test case annotations

One big change is the introduction of annotations so that you don’t have to follow the strict naming convention in previous versions where a test case method must start with the “test” prefix. I personally think it’s actually a nice convention. Even the restriction is removed, I still see most people stick with the convention. But then you have to add additional @Test annotation. For that, it’s a step back from the “convention over configuration” movement initiated in the Ruby On Rail framework. With the annotations, it does simplifies the code, for example, the exception handling test, timeout setting. So overall I think it’s a good move.

The following is a sample that illustrates the usage of annotations. The first class is the code to be tested, as known as production code which is overly simplified here. The second class is the test case class.

package org.doublecloud.sample.junit.hello;
 
public class HelloUnit
{
  public int add(int x, int y)
  {
    return x + y;
  }
}
 
package org.doublecloud.sample.junit.test;
 
import static org.junit.Assert.assertEquals;
 
import java.rmi.RemoteException;
 
import org.doublecloud.sample.junit.hello.HelloUnit;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Ignore;
import org.junit.Test;
 
public class HelloUnitTest
{
  private static HelloUnit helloUnit;
 
  @BeforeClass
  public static void setUpBeforeClass() throws Exception
  {
    helloUnit = new HelloUnit();
  }
 
  @AfterClass
  public static void tearDownAfterClass() throws Exception
  {
  }
 
  @Before
  public void setUp() throws Exception
  {
  }
 
  @After
  public void tearDown() throws Exception
  {
  }
 
  // You can optionally put timeout as follows in milliseconds
  //@Test(timeout=10)
  @Test
  public void testAdd()
  {
    assertEquals(5, helloUnit.add(2, 3));
  }
 
  @Ignore
  @Test
  public void testMoreToBeIgnored()
  {
  }
 
  // this test will succeed as it does raise the expected exception
  @Test(expected = IndexOutOfBoundsException.class)
  public void testException()
  {
    int[] array = new int[] { 1, 2 };
    System.out.println("Last item in array: " + array[2]);
  }
 
  // this test will result in an error
  @Test(expected = RemoteException.class)
  public void testExceptionError()
  {
    int[] array = new int[] { 1, 2 };
    System.out.println("Last item in array: " + array[2]);
  }
}

Note that most Java IDEs like Eclipse help generate the basic skeleton of a test case class for a selected production class. All you need to do is to pick whatever methods you want to include and later implement the code with test logic. Once the test case class is done, you can run it in a simple way to run a Java class with main() defined. In Eclipse, the test result is shown in the JUnit view with summary and breakdowns in a pretty intuitive way.

This is nice but really enough. You want to run it after your building your production code. There are nice integration already with for example Ant.

Inheritance Made Possible

The other improvement is the lift of restriction on the forced inheritance of TestCase. As we all know, Java supports single inheritance, meaning if a test class has TestCase as its super class, it cannot inherit any other classes. It limits the code sharing within the test cases via inheritance. If you really want to share code, you have to use utility classes. With this improvement, you can start to think about the inheritance hierarchy. It may not be a big deal for small project but may for a big project with comprehensive test cases.

The sample to be listed in the next section will shows the inheritance. There is no difference for the usage of inheritance in test case classes than other normal classes.

Parameterized Testing: New Level of Abstraction

The last improvement I see of some values is the parameterized testing. It’s another level of abstraction where you can reduce similar tests with different sets of test data into a single meta class that instantiates a new test case per set of test data.

The following test case class illustrates how to achieve this and the inheritance discussed in last section.

package org.doublecloud.sample.junit.test;
 
import java.util.Arrays;
import java.util.Collection;
 
import org.junit.runner.RunWith;
import org.junit.runners.Parameterized;
import org.junit.runners.Parameterized.Parameters;
 
@RunWith(Parameterized.class)
public class ParameterizedHelloUnitTest extends HelloUnitTest
{
  int[] adds;
  int sum;
 
  public ParameterizedHelloUnitTest(int[] adds, int sum)
  {
    this.adds = adds;
    this.sum = sum;
  }
 
  @Parameters
  public static Collection<?> regExValues()
  {
    return Arrays.asList(new Object[][] {
            { new int[] { 1, 2 }, 3 },
            { new int[] { 100, 2 }, 102 },
            { new int[] { Integer.MAX_VALUE, Integer.MAX_VALUE }, Integer.MAX_VALUE } });
  }
}

Test suite for grouping

The test suite concept continues to exist in JUnit 4 as the grouping mechanism. Again, it’s not inherited from TestSuite class as before, but annotated with @SuiteClasses and @RunWith as shown in following. As you can see, there is really not much in the class itself exception the annotations that come before it.

package org.doublecloud.sample.junit.test;
 
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
import org.junit.runners.Suite.SuiteClasses;
 
@RunWith(Suite.class)
@SuiteClasses({ ParameterizedHelloUnitTest.class, HelloUnitTest.class })
public class HelloTestSuite
{
}

This is really a brief introduction of JUnit 4. The key takeaways are the new features introduced in JUnit 4: annotations, inheritance among test cases, and parameterized test cases. As always, try the samples for better and deeper understanding of the unit testing.

This entry was posted in Software Development and tagged , , , . Bookmark the permalink. Post a comment or leave a trackback: Trackback URL.

One Comment

  1. philips
    Posted July 20, 2016 at 9:03 am | Permalink

    Test Suit concept for JUnit 4 is explained here very excellently. This is initial level coding for programming but very useful. I wholeheartedly appreciate blogger smart work.

Post a Comment

Your email is never published nor shared. Required fields are marked *

*
*

You may use these HTML tags and attributes <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <s> <strike> <strong>

  • NEED HELP?


    My company has created products like vSearch ("Super vCenter"), vijavaNG APIs, EAM APIs, ICE tool. We also help clients with virtualization and cloud computing on customized development, training. Should you, or someone you know, need these products and services, please feel free to contact me: steve __AT__ doublecloud.org.

    Me: Steve Jin, VMware vExpert who authored the VMware VI and vSphere SDK by Prentice Hall, and created the de factor open source vSphere Java API while working at VMware engineering. Companies like Cisco, EMC, NetApp, HP, Dell, VMware, are among the users of the API and other tools I developed for their products, internal IT orchestration, and test automation.