JUnit 4 Test Suite Tutorial Example

To start with we create a new project in eclipse using following command:

mvn archetype:generate -DartifactId=junitTestSuiteExample -DgroupId=com.thecafetechno.www.junit_example -DarchetypeArtifactId=maven-archetype-quickstart

This will create a new project named junitTestSuiteExample. Add dependency for junit, the resultant pom.xml will look like

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
  xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd">
  <modelVersion>4.0.0</modelVersion>
  <groupId>com.thecafetechno.www.junit_example</groupId>
  <artifactId>junitTestSuiteExample</artifactId>
  <packaging>jar</packaging>
  <version>1.0-SNAPSHOT</version>
  <name>junitTestSuiteExample</name>
  <url>http://maven.apache.org</url>
  <dependencies>
    <dependency>
      <groupId>junit</groupId>
      <artifactId>junit</artifactId>
      <version>4.5</version>
      <scope>test</scope>
    </dependency>
  </dependencies>
</project>

Move to this project folder and run following commands:
mvn clean install
mvn eclipse:clean eclipse:eclipse

Import this project in eclipse and create a new package com.thecafetechno.www.junit_example in src/main/java folder. Create three classes in this package:
FirstClass.java

package com.thecafetechno.www.junit_example;

public class FirstClass {
	public String firstMethod() {
		return "first class method";
	}
}

SecondClass.java

package com.thecafetechno.www.junit_example;

public class SecondClass {
	public String secondMethod() {
		return "second class method";
	}
}

ThirdClass.java

package com.thecafetechno.www.junit_example;

public class ThirdClass {
	public String thirdMethod() {
		return "third class method";
	}
}

Create three testclasses in src/test/java in a new package com.thecafetechno.www.junit_example
TestFirstClass.java

package com.thecafetechno.www.junit_example;

import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestFirstClass extends TestCase {
	FirstClass firstClass;
	
	@Before
	public void setUp() {
		firstClass = new FirstClass();
		System.out.println("setup for first class");
	}
	
	@Test
	public void testFirstMethod() {
		String result = firstClass.firstMethod();
		assertEquals("first class method", result);
	}
	
	@After
	public void tearDown() {
		firstClass=null;
		System.out.println("tear down for first class");
	}
	
}

TestSecondClass.java

package com.thecafetechno.www.junit_example;

import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestSecondClass extends TestCase{
	SecondClass secondClass;
	
	@Before
	public void setUp() {
		secondClass = new SecondClass();
		System.out.println("setup for second class");

	}
	
	@Test
	public void testFirstMethod() {
		String result = secondClass.secondMethod();
		assertEquals("second class method", result);
	}
	
	@After
	public void tearDown() {
		secondClass=null;
		System.out.println("tear down for second class");
	}
	
}

TestThirdClass.java

package com.thecafetechno.www.junit_example;

import junit.framework.TestCase;

import org.junit.After;
import org.junit.Before;
import org.junit.Test;

public class TestThirdClass extends TestCase {
	ThirdClass thirdClass;
	
	@Before
	public void setUp() {
		thirdClass = new ThirdClass();
		System.out.println("setup for third class");
	}
	
	@Test
	public void testFirstMethod() {
		String result = thirdClass.thirdMethod();
		assertEquals("third class method", result);
	}
	
	@After
	public void tearDown() {
		thirdClass=null;
		System.out.println("tear down for third class");
	}
	
}

To create a test suite we annotate our class with

@RunWith(Suite.class)

When a class is annotated with @RunWith or extends a class annotated with @RunWith, JUnit will invoke the class it references to run the tests in that class instead of the runner built into JUnit.

@SuiteClasses – JUnit 4.4 class annotation that specify an array of test classes for the Suite.class to run.

We will now run create the test suite class to run these test in com.thecafetechno.www.junit_example.testsuite package.
Tester.java

package com.thecafetechno.www.junit_example.testsuite;

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

import com.thecafetechno.www.junit_example.TestFirstClass;
import com.thecafetechno.www.junit_example.TestSecondClass;
import com.thecafetechno.www.junit_example.TestThirdClass;

@RunWith(Suite.class)
@SuiteClasses({TestFirstClass.class, TestSecondClass.class, TestThirdClass.class})
public class Tester {

}

When run following will be output

setup for first class
tear down for first class
setup for second class
tear down for second class
setup for third class
tear down for third class

You can find the zip file for source code here

Difference Between Junit3 and Junit4 tutorial

1) Junit4 test cases no longer need to extend junit.framework.TestCase class. Any class with zero argument constructor can act as a test class

2) Test case names no longer need to follow testXXX pattern. Any method that we want to be considered as test method needs to be annotated with @Test in Junit4

3) Instead of setUp() and tearDown() methods which are executed before and after each test case in Junit3, we can annotate any number of methods that we want to execute before every test case by @Before annotation. Similarly methods that we want to be executed after each test case can be annotated by @After.

However @Before and @After annotated methods must be public and return void.

4) If we want some common methods that must be executed not before and after each test case but a whole set of test, we can annotate them with @BeforeClass and @AfterClass.

For example if we want some resource setup code which sets up same resources for each test case in class ex. database connectivity code can be annotated with @BeforeClass

5) We can ignore some test cases using @Ignore annotation.

6) Way of testing a test case for exception has also changed in Junit4.

In Junit3 we fail a test case deliberately if exception is not thrown, as shown below.

public void testSomeException() {
SomeClass c = new SomeClass();
try {
c.meth();
fail("Exception should have been thrown, but was not");
} catch (SomeException expected) {
assertTrue(true);
}
}

In Junit4 we use a expected in @Test annotation to denote that method is supposed to throw an exception of th type provided

@Test(expected=SomeException.class)
public void testSomeException() {
SomeClass c = new SomeClass ();
c.meth();
}

7) In Junit4 we have an additional parameter timeout which denote an upper time limit on execution of test. If this time limit exceeds, the test is marked as failed and n exception is raised. The code snapshot is shown below:
@Test(timeout=50)
public void testSomeMethodSupposedToBeFinishedIn50MilliSeconds() {
[...]
}

Back to Junit Interview Questions and Answers

What is mocking? Why use mock objects in unit testing?

Mocking allows you to test a class or a method in isolation. A class or method can be dependent on many other classes or methods. It is with the help of others(collaborators) a class or method completes its functionality. In mocking we replace all of its collaborators with mocks that essentially simulate the normal environment of the class/method.

Mock Objects can be defined as:

Any dummy object that stands in for a real object that is not available, or is difficult to use in a test case. A mock object must have the ability to set up expectations and provide a self-validation mechanism.

Why use Mock Objects?

  • Mock objects help us to test a component in isolation from the rest of the system.
  • With mock objects we just test the core functionality of the class or method and we don’t have to test the collaborators.
  • Mock objects help us to test unusual, unlikely, and exceptional situations.
  • Mock objects make it easier to write code for problematic resources.
  • Mock objects make tests run faster.
  • Mock objects promote interface-based design and encourage composition over inheritance.

Unit Testing Using Junit and Easymock

An Introduction to Unit Testing:

Unit Testing focuses on verification of smallest unit of software, i.e. a component or a module. Unit tests test following features of component:

• Interface: To verify proper flow of information in and out of component.
• Local Data Structures: To verify integrity of data during all steps of algorithm
• Boundary Conditions: To ensure component works properly at boundaries
• Independent Paths: To ensure all independent paths have been exercised so as to cover every statement
• Error Handling Paths: To cover all error handling paths ex. exception handling paths.
Unit tests allow a programmer or developer to ensure that:
• All features are correctly implemented
• Only required features are implemented(If we talk about test driven development)
• Maintenance hasn’t broken any existing code. If executing test case post maintenance breaks any of existing test cases, this indicates change of existing functionality by new work.

JUnit is testing framework for unit testing, which is usually used in conjunction with EasyMock.
Reader can find JUnit tutorial here
for EasyMock tutorial with junit please refer here

Easymock tutorial

As stated above unit testing is testing a component in isolation. JUnit is a framework which helps us perform unit testing. To test a component in isolation, we may need to mock some components.

To start with we write a class Student that we will use in our example. We already tested this class Student using junit in previous turorial here. For sake of completion of this tutorial we again present code of this class Student

package com.thecafetechno.organisation;

public class Student {
	String name;
	int marks;
	int year;

	public String getName() {
		return name;
	}

	public void setName(String name) {
		this.name = name;
	}

	public int getMarks() {
		return marks;
	}

	public void setMarks(int marks) {
		this.marks = marks;
	}

	public int getYear() {
		return year;
	}

	public void setYear(int year) {
		this.year = year;
	}

	public boolean isStudentInFirstGrade() {
		boolean result = false;
		if (marks > 75) {
			result = true;
		}
		return result;
	}

	public String returnGrade() {
		String grade = null;
		if (marks < 40) {
			grade = "fail";
		} else if (marks < 60) {
			grade = "third";
		} else if (marks < 75) {
			grade = "second";
		} else {
			grade = "first";
		}
		return grade;
	}

	// this method sums up the total
	// fees paid by a student assuming
	// annual fee is 20000
	public int getTotalFeesPaid() throws YearFormatException {
		int sum = 0;
		if (year < 0) {
			throw new YearFormatException();
		}
		for (int i = 0; i < year; i++) {
			sum = sum + 20000;
		}
		return sum;
	}

	@Override
	public boolean equals(Object obj) {
		return this.getName().equals(((Student) obj).getName());
	}
}

class YearFormatException extends Exception {

}

To further understand need of mocking, assume that our class under test which we say host class is associated with some other class i.e. it has reference variable for some other class as its property value and host class calls the methods of other class through its reference variable in its own methods. As an example consider following class StudentProcessor:

package com.thecafetechno.organisation;

public class StudentProcessor {

	// depends on StudentDataService to fetch data
	// from database
	StudentDataService studentDataService;
	// depends on GradeAmountCalculator to calculate
	// scholarship amount based on marks obtained by
	// student.
	GradeAmountCalculator gradeAmountCalculator;
	// deductAmount(int amount) deletes the amount from
	// total funds allocated
	FundsManager fundsManager;

	public FundsManager getFundsManager() {
		return fundsManager;
	}

	public void setFundsManager(FundsManager fundsManager) {
		this.fundsManager = fundsManager;
	}

	public StudentDataService getStudentDataService() {
		return studentDataService;
	}

	public void setStudentDataService(StudentDataService studentDataService) {
		this.studentDataService = studentDataService;
	}

	public GradeAmountCalculator getGradeAmountCalculator() {
		return gradeAmountCalculator;
	}

	public void setGradeAmountCalculator(
			GradeAmountCalculator gradeAmountCalculator) {
		this.gradeAmountCalculator = gradeAmountCalculator;
	}

	public Student getStudent(String name) throws StudentNotFoundException {
		Student student = studentDataService.loadStudent(name);
		return student;
	}

	public int calculateScholarship(Student student) {
		int scholarshipAmount = 0;
		scholarshipAmount = gradeAmountCalculator
				.calculateGradeBasedAmount(student.getMarks());
		if (student.getYear() == 1) {
			scholarshipAmount = scholarshipAmount + 200;
		} else if (student.getYear() == 2) {
			scholarshipAmount = scholarshipAmount + 500;
		} else if (student.getYear() == 3) {
			scholarshipAmount = scholarshipAmount + 1000;
		} else if (student.getYear() == 4) {
			scholarshipAmount = scholarshipAmount + 1500;
		}
		fundsManager.deductAmount(scholarshipAmount);
		return scholarshipAmount;
	}
}

Also make exception class named StudentNotFoundException.java

package com.thecafetechno.organisation;

public class StudentNotFoundException extends Exception {

}