By kswaughs | Sunday, August 16, 2015

Junit tutorial

JUnit is an open source unit testing framework designed by Kent Beck, Erich Gamma for the purpose of writing and running test cases for java programs. That java program can be either a small program or a complex architecture applications like web services and web applications.

In case of web applications and web services, JUnit is used to test the application with out deploying in any server. This framework builds a relationship between development and testing process.

UNIT Testing is a software testing method by which individual units of source code are tested to determine whether they are fit for use and working as it should be. The primary goal of unit testing is to take the smallest piece of testable software in the application, isolate it from the remainder of the code, and validate its behavior. Individual unit might be a method of a class, group of classes.

WHERE THIS COMES INTO PICTURE

In the real world, to manufacture any product it should go through several phases of its life cycle. Similarly to develop a software for a user requirement, it should go through all the phases of below software development project life cycle.

  • Analysis 
  • Design 
  • Build 
  • Testing 
  • Production 
  • Maintenance

Most of the guys think that Unit testing is a part of ‘Testing’ phase as the name contains word testing. But this is wrong. Unit testing is a build activity and developers have to write and run the tests to make sure the code they written are working properly.

Benefits of writing JUNIT tests.

  • Ensures a quality and bug free code is delivered.
  • Issues and defects can be identified early in build phase.
  • Less or zero defects related to functionality will be raised in testing phase.
  • No need to deploy our code in any server to test the functionality.

STRUCTURE OF JUNIT CLASS

JUnit is also a java class written with some test methods to test the actual code. Usually the code that we want to test is a Java method which takes some input as method arguments and provides the output as a method return type. That method may return different kinds of response based on input values or some back-end data. So, we write different test methods to validate all the scenarios by providing the input accordingly.

Basic structure of the Junit class
import org.junit.*;
import static org.junit.Assert.*;
import java.util.*;
 
/**
 * @author Srinivas
 *
 */
public class SampleJunitTest {
 
    @BeforeClass
    public static void oneTimeSetUp() {
        // one-time initialization code   
     System.out.println("@BeforeClass - oneTimeSetUp : Runs before all test methods");
    }
 
    @AfterClass
    public static void oneTimeTearDown() {
        // one-time cleanup code
    System.out.println("@AfterClass - oneTimeTearDown : Runs after all test methods");
    }
 
    @Before
    public void setUp() {
        System.out.println("@Before - setUp : Runs before every test method");
    }
 
    @After
    public void tearDown() {
         System.out.println("@After - tearDown : Runs after every test method");
    }
 
    @Test
    public void testMyMethodUseCase1() {
         System.out.println("@Test - testMyMethodUseCase1 : Actual test method");
    }
 
    @Test
    public void testMyMethodUseCase2() {
        System.out.println("@Test - testMyMethodUseCase2 : Another test method");
    }
}
Result

@BeforeClass - oneTimeSetUp : Runs before all test methods
@Before - setUp : Runs before every test method 
@Test - testMyMethodUseCase1 : Actual test method
@After - tearDown : Runs after every test method
@Before - setUp : Runs before every test method 
@Test - testMyMethodUseCase2 : Another test method
@After - tearDown : Runs after every test method
@AfterClass - oneTimeTearDown : Runs after all test methods

How to define a test in JUnit ?

A JUnit test is a method contained in a class which is only used for testing. This is called a Test class. To write a test with the JUnit 4.x framework you annotate a method with the @org.junit.Test annotation. In this method you use an assert method, typically provided by the JUnit or another assert framework, to check the actual result of a method call is same as expected result. These method calls are typically called asserts or assert statements.

You should provide meaningful messages in assert statements so that it is easier for the developer to identify the problem. This helps in fixing the issue, especially if someone looks at the problem, who did not write the code under test or the test code.

JUnit naming conventions

There are several potential naming conventions for JUnit tests. In widespread use is to use the name of the class under test and to add the

  •   "Test" suffix to the test class
  •   “test” prefix to the test method

For the test method names it is frequently recommended to use the meaningful business use case, as for example "testWhenAccountIsInactive" or "testWhenUserNameisInvalid" as this gives a good hint what should happen if the test method is executed. As a general rule, a test name should explain what the test does so that it can be avoided to read the actual implementation.

JUnit test suites

If you have several test classes, you can combine them into a test suite. Running a test suite will execute all test classes in that suite in the specified order. The “Suite Test” means bundle a few unit test cases and run it together. In Junit, both @RunWith and @Suite annotations are used to run the suite test.

The below example means both unit test EmployeeTest and CustomerTest will run together after MyJunitTest is executed.

Sample Test Suite Configuration
import org.junit.runner.RunWith;
import org.junit.runners.Suite;
 
@RunWith(Suite.class)
@Suite.SuiteClasses({
        EmployeeTest.class,
        CustomerTest.class
})
public class MyJunitTest {

}

Basic JUnit code constructs and annotations

JUnit 4.x uses annotations to mark methods as test methods and to configure them. The following table gives an overview of the most important annotations in JUnit.

JUNIT Annotations

@Test

@Test
public void method()

The @Test annotation identifies a method as a test method.

@Test (expected = Exception.class)

Fails if the method does not throw the named exception

@Test(timeout=100)

Fails if the method takes longer than 100 milliseconds.

@Before

@Before
public void method()

This method is executed before each test. It is used to prepare the test environment (e.g., read input data, initialize the class).

@After

@After
public void method()

This method is executed after each test. It is used to clean up the test environment (e.g., delete temporary data, restore defaults). It can also save memory by cleaning up expensive memory structures.

@BeforeClass

@BeforeClass
public static void method()

This method is executed once, before the start of all tests. It is used to perform time intensive activities, for example, to connect to a database. Methods marked with this annotation need to be defined as static to work with JUnit.

@AfterClass

@AfterClass
public static void method()

This method is executed once, after all tests have been finished. It is used to perform clean-up activities, for example, to disconnect from a database. Methods annotated with this annotation need to be defined as static to work with JUnit.

@Ignore

@Ignore("Why disabled")

Ignores the test method. This is useful when the underlying code has been changed and the test case has not yet been adapted. Or If the execution time of this test is too long to be included. It is best practice to provide the optional description, why the test is disabled.

In JUnit 4, you have to declare “@BeforeClass” and “@AfterClass” methods as static methods.

Assert statements

JUnit provides static methods in the Assert class to test for certain conditions. These assert statements typically start with assert and allow you to specify the error message, the expected and the actual result. An assertion method compares the actual value returned by a test to the expected value, and throws an AssertionException if the comparison test fails.

The following table gives an overview of these methods. Parameters in [] brackets are optional and of type String.

Assert Statements

fail(message)

Let the method fail. Might be used to check that a certain part of the code is not reached or to have a failing test before the test code is implemented. The message parameter is optional.

assertTrue([message,] boolean condition)

Checks that the boolean condition is true.

assertFalse([message,] boolean condition)

Checks that the boolean condition is false.

assertEquals([message,] expected, actual)

Verifies that two values are the same. For arrays the reference is checked not the content of the arrays.

assertEquals([message,] expected, actual, tolerance)

Test that float or double values match. The tolerance is the number of decimals which must be the same.

assertNull([message,]object)

Checks that the object is null.

assertNotNull([message,] object)

Checks that the object is not null.

assertSame([message,] expected, actual)

Checks that both variables refer to the same object.

assertNotSame([message,] expected, actual)

Checks that both variables refer to different objects.

Test Methods.

Basically In Java, a functional method either returns a response object or throw some exceptions based on the business use case. When we are writing a unit test means, in test method we call the java method by passing required input data and validate the output object.

In the below example, We are testing UserService class that has a method called ‘getUserById’ which will return User object for the requested userId, if userid not found it throws UserNotFoundException.

Case 1: Validate the exception thrown by method
import org.junit.*;

public class SampleTest {

 private UserService userSvc;

 @Before
 public void setUp() {
        userSvc = new UserService();
  }

@Test(expected = UserNotFoundException.class)  
 public void testWhenInvalidUserIdIsPassed() {  
     userSvc.getUserById(“NOEMP45678”);
  }  
}

In the below example, We are testing again the same method as above but this time we are validating the message of the exception.

Case 2: Validate the error message in the exception thrown by method
import static org.junit.Assert.assertEquals;
import org.junit.*;
 
public class SampleTest {

 private UserService userSvc;

 @Before
 public void setUp() {
        userSvc = new UserService();
  }

@Test 
 public void testWhenInvalidUserIdIsPassed() {  
    try {
         userSvc.getUserById(“NOEMP45678”);
         Assert.fail("Should throw exception"); 
    } catch(UserNotFoundException exp) {
       assertEquals("Invalid Employee ID Format",exp.getMessage() );
    }
 }  
}

In the below example, We are testing the same method and validating the values of response object returned by that method.

Case 3: Validate the response object returned by method
import static org.junit.Assert.assertEquals;
import org.junit.*;
 
public class SampleTest {

private UserService userSvc;

 @Before
 public void setUp() {
        userSvc = new UserService();
  }

@Test 
 public void testWhenUserDetailsFound() throws Exception{  
      User user = userSvc.getUserById(“EMP341234”);
         
       assertEquals("EMP341234", user.getUserId() );
       assertEquals("JOHN", user.getUserName() );

     }  
}
 

Test execution order

JUnit assumes that all test methods can be executed in an arbitrary order. Well-written test code should not assume any order, i.e., tests should not depend on other tests. As of JUnit 4.11 the default which may vary from run to run. It is to use a deterministic, but not predictable, order for the execution of the tests.

You can use an annotation to define that the test methods are sorted by method name, in lexicographic order. To activate this feature, annotate your test class with the @FixMethodOrder(MethodSorters.NAME_ASCENDING) annotation. You can also explicitly set the default by using the MethodSorters.DEFAULT parameter in this annotation. You can also use MethodSorters.JVM which uses the JVM defaults, which may vary from run to run.

This article described Junit tutorial about the concepts of Junit framework and covered with sample examples. This seems so simple. Isn't right ?. The above discussed components are enough to write junit test cases as long as your java classes are independently implemented with out depending on any other back-end or external systems.

What If classes are back end dependant. Can't we write Junit test cases ?

Yes. You can still write junit test cases but the problem is that your classes will try to connect to those systems and you will get unexpected errors. If you provide all the back-end set up details then it will become an integration testing but not an unit test. The purpose of unit testing itself is to test the functionality of our java classes individually without depending on availability of back-end systems. In such cases, you have to use mocking frameworks like JMock, EasyMock or Mockito to by pass the actual methods of dependant classes. There is nothing to worry which one should you use. All java based mocking frameworks can be easily integrated into Junit, the difference will be in using the mocking methods provided by them.

Recommend this on


No comments:

Post a Comment