Mocking db calls in unit test

Here is my java class which is accessing DB to fetch movie names and then it validates if the fetched movie name has a movie called ‘Sangam’.

package com.sanjit;

import java.sql.*;

/**
* Class accessing the DB to fetch some data, which is then used for some
* validation
*
* @author Sanjit Mohanty
* @version 0.1
*
*          <pre>
* Revision History:
* VERSION  DATE           AUTHOR            COMMENT
* 0.1      21-Jul-2010    Sanjit Mohanty    initial create
* </pre>
*/

public class DBCallClass {

static Connection con;

public boolean isMovieSangam() throws SQLException {
ResultSet rs = fetchData();

while (rs.next()) {
String movieName = rs.getString("moviename");

if (movieName == "Sangam") {
return true;
}
}

return false;
}

public ResultSet fetchData() throws SQLException {

String connectionURL = "jdbc:postgresql://localhost:123456/movies;user=java;password=samples";

try {
Class.forName("org.postgresql.Driver");
con = DriverManager.getConnection(connectionURL);
Statement stmt = con.createStatement();
ResultSet rs = stmt.executeQuery("select moviename from movies");

return rs;
} catch (SQLException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
con.close();
}

return null;
}
}

In order to unit test the above class, i’ve to mock the actual DB call and then return the test data. I’ve used powermock (with easymock api) library to achieve this.

So, the JUnit class for the above looks as below:

import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.ResultSet;
import java.sql.Statement;
import org.junit.Assert;
import org.junit.Before;
import org.junit.Test;
import org.junit.runner.RunWith;

import static org.easymock.EasyMock.expect;
import static org.powermock.api.easymock.PowerMock.*;

import org.powermock.core.classloader.annotations.PrepareForTest;
import org.powermock.modules.junit4.PowerMockRunner;

import com.sanjit.DBCallClass;

/**
* Example: Mocking the DB calls using powermock. Main Class:
* {@link com.sanjit.DBCallClass}
*
* @author Sanjit Mohanty
* @version 0.1
*
*          <pre>
* Revision History:
* VERSION  DATE           AUTHOR            COMMENT
* 0.1      21-Jul-2010    Sanjit Mohanty    initial create
* </pre>
*/

@RunWith(PowerMockRunner.class)
@PrepareForTest({ DBCallClass.class, DriverManager.class })
public class DBCallClassTest {

private String connectionURL;
private String sql;
private boolean isMovieSangam;

@Before
public void initialization() {
connectionURL = "jdbc:postgresql://localhost:123456/movies;user=java;password=samples";
sql = "select moviename from movies";
isMovieSangam = false;
}

@Test
public void testIsMovieSangam() throws Exception {

// Create mocks and set expectations
createMocksAndSetExpectations();

// Instantiate the class under test
DBCallClass dbCall = new DBCallClass();

// Invoke the method to test
isMovieSangam = dbCall.isMovieSangam();

// Verify the results
doVerification();
}

private void createMocksAndSetExpectations() throws Exception {

Connection mockConnection = createMock(Connection.class);
Statement mockStatement = createMock(Statement.class);
ResultSet mockResultSet = createMock(ResultSet.class);

// Mocking Static Class
mockStatic(DriverManager.class);
expect(DriverManager.getConnection(connectionURL)).andReturn(
mockConnection);
replay(DriverManager.class);

expect(mockConnection.createStatement()).andReturn(mockStatement)
.anyTimes();
mockConnection.close();
replay(mockConnection);

expect(mockStatement.executeQuery(sql)).andReturn(mockResultSet);
replay(mockStatement);

expect(mockResultSet.next()).andReturn(true);
expect(mockResultSet.getString("moviename")).andReturn("Sangam");
replay(mockResultSet);
replay(mockStatement);
}

private void doVerification() {
Assert.assertEquals(true, isMovieSangam);
}
}

To use powermock (with easymock api) in a maven project, include the following dependencies to the pom.xml file:

<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-module-junit4</artifactId>
<version>1.4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.powermock</groupId>
<artifactId>powermock-api-easymock</artifactId>
<version>1.4.9</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.easymock</groupId>
<artifactId>easymock</artifactId>
<version>3.0</version>
</dependency>

But if you are using a non-maven based java project then you need to place cglib-nodep-2.2.2.jar,
easymock-3.1.jar, javassist-3.16.1-GA.jar, powermock-easymock-1.4.12-full.jar, powermock-module-junit4-1.4.12.jar
and objenesis-1.2.jar in your classpath. Pl. note versions are just an indicator, you should use the latest
versions of these jars.