Unit Testing - Junit Approach
Unit Testing involves testing unit components or modules of Code and validating that they work properly. It’s a proactive procedure, which means that code written by developers needs to be unit tested at the unit level. All test cases are independent of each other and are to be written and executed by development team.
Prior fixing a bug, write a unit test to reproduce it. When the bug is fixed, verify the fix using the unit test. All methods need to be covered by the tests. The tests need to covers all paths through the unit. Unit Tests will ensure errors are picked up at the earlier stage and will facilitate easy integration.
Unit Testing Process
The figure below illustrates the Unit Testing Procedure and it encourages developers to write test cases before they start developing their use cases.
Guidelines for Unit Test Cases
- Write the test before implementing the functionality using a test driven approach. Every software component (business modules, services, DAOs, models or controllers of the presentation tier) will be designed to be tested.
- When a bug is identified in the code and later fixed, as a good practice write a unit test to validate it.
- Use Mock Object to collaborate with other components.
- Write the tests for normal success case, boundary conditions or any exceptional conditions.
- Make a decision if it’s really appropriate to write tests for simple methods or simple classes. These will get tested later during Integration Testing (like DTOs, get/set,..).
- Unit Test for Business Objects that only encapsulate data is not necessary. Only if the BO implements Business Logic, then this has to be tested using a unit test.
- While testing the Business Logic Layer, unit tests need to be written for every service interface. Use Mock Objects for DAO’s. Components used within the service implementation that contain validation logic will need to be tested independently. E.g. Validators, Convertors.
- For the Presentation Layer one would need to set up the page, pageView, pageModel and the PageContext. Mock Objects will be used to model the PageContext.
- The Test Coverage should be continuously monitored. Clover/ Cobertura could be used to for code coverage.
- The names of Java source files for testing end with ‘Test’, as in MyClassTest.java.
- While testing the Data Access Layer, make sure every DAO method has been tested. After each test the transaction should be rolled back so cleaning of the database is not required. (spring framework will do job of automatic rollback of data changes to the database).
Unit Testing Tools
Consider a combination of JUnit and EasyMock to write Unit Test Cases. These tools are integrated with Eclipse (hopefully with Intellij) to merge unit tests with the development process.
Unit Testing Framework - JUnit
JUnit provides a Java based framework for unit testing. In order to setup JUnit one has to download the junit.jar file which is freely downloadable and append it to your classpath. JUnit will be integrated with the Eclipse development environment.
- While writing unit tests, any class that contains test methods should subclass the TestCase class. A TestCase can define any number of public testXXX() methods.
- To check the expected and the actual test results, one has to invoke the variation of assert() method.
- The Test Class having several testXXX() methods can use the setup() and teardown() methods to initialize and release any common objects under test.
- TestCase instances can be composed into TestSuite hierarchies so that all test methods are invoked
EasyMock
EasyMock, an open source library provides an easy medium to generate mock objects for a given interface. This facilitates running Junit tests for individual classes with the collaborators being simulated with Easy Mock Objects.
To get a Mock Object, we need to perform the following steps:
- Create a Mock Object for the interface we would like to simulate
- Setup the Expected behavior. Record the expected method calls.
- Switch the Mock Object to replay state. If no expected behavior is set, then call to any methods of the collaborator class with throw an exceptions.
- Call object under test
- Validate if the expectations have been met.
- Code Snippet using JUnit & EasyMock
import junit.framework.TestCase;
import static org.easymock.EasyMock.createMock;
import static org.easymock.EasyMock.expect;
import static org.easymock.EasyMock.replay;
import static org.easymock.EasyMock.reset;
import static org.easymock.EasyMock.verify;
public class UserServiceImplTest extends TestCase {
private UserDao userDaoMock;
private UserService us;
public void setUp() throws Exception {
// 1. create the mock for our DAO
userDaoMock = createMock(UserDao.class);
// 2. create an instance of the class under test
us = new UserServiceImpl();
// 3. wire test object and mock
us.setUserDao(userDaoMock);
}
/**
* after each test method call the mock has to be reset
*/
public void tearDown() throws Exception {
reset(userDaoMock);
}
}
Written by Ravi Nallakukkala on April 8th, 2007 with no comments.
Read more articles on Design.