JUnit Testing Using EasyMock
EasyMock and JUnit can work together to make unit testing your Java code much easier through the use of proxy objects.
Join the DZone community and get the full member experience.
Join For FreeJUnit is one of the most popular frameworks for performing Java UT. Mocking is also an aspect that goes hand in hand with JUnit. Unit testing is, of course, performed by developers to test the code they've written.
Let’s consider:
Developer 1 has developed business logic code.
Developer 2 has developed persistence logic code (code that interacts with the database).
If Developer 1 has to use the persistence logic code (method call) written by Developer 2, then Dev 1 might mock that method call. Doing so will let the developer focus only on that code to test it. It’s more like staying in an environment and just testing the code in that environment itself.
While unit testing, developers just test the code in the same environment and mocks the interaction with any other environment.
A more real-time example would be where the code has to interact with the payment gateway. For UT, a developer might not want to send requests to the payment gateway.
Actual interactions with the payment gateway might be done during the SIT (System Integrated Testing ) phase.
There are many frameworks for mocking; Mockito and EasyMock are two of the most popular frameworks. I will be using EasyMock in the example below. Mocking is the process of using a fake object during the UT phase. These frameworks do this by generating proxy objects (java.lang.reflect.Proxy). However, for these purposes, you don't need to know the details about proxy objects.
I will just be using a simple editor for the example, as it will allow for better understanding of the implementations that an IDE might not be able to show.
We will need following JARs:
mysql-connector-java-5.1.6-bin.jar <Your JDBC driver, incase you don't mock>
junit-4.11-beta-1.jar
hamcrest-core-1.3.RC2.jar
easymock-3.2.jar
cglib-nodep-2.2.2.jar
objenesis-1.2.jar
There are four java files for this example.
Student.java (POJO Class)
StudentDAO.java
StudentCheck.java
StudentTest.java <JUnit Test Class>
Here, I am using the data type as String for rollNo (though ideally, it should be int). I'm just using a String for the sake of this example.
public class Student
{
private String rollNo;
private String firstname;
private String lastname;
private String dept;
public String getRollNo(){
return rollNo;
}
public void setRollNo(String rollNo){
this.rollNo = rollNo;
}
public String getFirstname(){
return firstname;
}
public void setFirstname(String firstname){
this.firstname = firstname;
}
public String getLastname(){
return lastname;
}
public void setLastname(String lastname){
this.lastname = lastname;
}
public String getDept(){
return dept;
}
public void setDept(String dept){
this.dept = dept;
}
public String toString(){
return "\n Roll No: "+rollNo+ "\n Firstname :" +firstname+ "\n Lastname : "+lastname+ "\n Dept : "+dept;
}
}
This is the DAO class that actually hits the database.
import java.sql.*;
public class StudentDAO{
public Student getStudentDetails(String rollNo) throws Exception{
System.out.println("Actual DB call will occur......");
Class.forName("com.mysql.jdbc.Driver");
Connection con = DriverManager.getConnection("jdbc:mysql://localhost:3306/trial","root","root");
PreparedStatement ps = con.prepareStatement("select * from Student where rollno=?");
Student stud = new Student();
ps.setString(1,rollNo);
ResultSet rs= ps.executeQuery();
while(rs.next()){
stud.setRollNo(rs.getString("rollno"));
stud.setFirstname(rs.getString("firstname"));
stud.setLastname(rs.getString("lastname"));
stud.setDept(rs.getString("dept"));
}
return stud;
}
}
Please note that there is an SOP on line 6, which prints on the console if the code hits the database.
System.out.println("Actual DB call will occur......");
StudentCheck.java is the class that calls the getStudentDetails() method of the StudentDAO.java class.
public class StudentCheck{
private StudentDAO studDAO = null;
public Student getDetails(String rollNo) throws Exception{
System.out.println("Before DB Call");
Student stud = studDAO.getStudentDetails(rollNo);
System.out.println("After DB Call");
return stud;
}
public void setStudDAO(StudentDAO studDAO){
this.studDAO = studDAO;
}
}
Now, StudentTest.java is the Test class where the actual action happens. This class has JUnit and the EasyMock API.
The EasyMock framework creates a proxy object/fake object of the class that we want to mock, and this proxy object can be used to return whatever you want as a return value of any of the methods of this class.
import static org.junit.Assert.*;
import org.junit.Test;
import org.easymock.*;
public class StudentTest {
@Test
public void testGetDetails001() throws Exception{
String rollNo= "111";
StudentDAO studentDAO = EasyMock.createMock(StudentDAO.class);
Student student = new Student();
student.setRollNo("111");
EasyMock.expect(studentDAO.getStudentDetails(EasyMock.isA(String.class))).andReturn(student);
EasyMock.replay(studentDAO);
StudentCheck studentCheck = new StudentCheck();
studentCheck.setStudDAO(studentDAO);
Student stud = studentCheck.getDetails(rollNo);
assertEquals("111",stud.getRollNo());
}
}
We can compare an EasyMock object to a tape.
createMock(): Blank Tape.
expect(): Recording your favorite song.
replay(): Playing your favorite song.
reset(): Erasing the tape, making it blank to record a new song.
Here, we are using EasyMock.isA(), but if we expect that a specific input is to be received by the method that mock, then we can set such expectations
EasyMock.expect(studentDAO.getStudentDetails("111")).andReturn(student);
This ensures that getStudentDetails() is expected ONLY when the input to the method is "111." For anything else, we get an exception.
Finally, we run our test class with the following command.
Please note "Actual DB call will occur......" is not printed on the console. This shows the DB was not hit.
Published at DZone with permission of Sourabh Bawage. See the original article here.
Opinions expressed by DZone contributors are their own.
Comments