How to Mock Resultset and Populate It Using Mockito in Java

Mocking Result Set using mockito

With your current implementation it's impossible to mock connection object, since Mockito unable to mock static calls, that is possible with PowerMockito. There is possible solution (feel free to change test logic, it's just a worked skeleton with mocks for you)

import static org.junit.Assert.assertEquals;
import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Matchers.eq;
import static org.mockito.Mockito.mock;
import static org.mockito.Mockito.when;

import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;

import org.junit.Test;
import org.junit.runner.RunWith;
import org.mockito.Mock;
import org.mockito.MockitoAnnotations;
import org.powermock.modules.junit4.PowerMockRunner;
import org.powermock.api.mockito.PowerMockito;
import org.powermock.core.classloader.annotations.PrepareForTest;
import java.util.Map;
import java.util.HashMap;

@RunWith(PowerMockRunner.class)
@PrepareForTest({ SqlConnectionUtil.class, RccSqlParameterMap.class })
public class TestQueryRunner {

@Test
public void testGetResultSetFromSql() throws SQLException {
ResultSet rs = mock(ResultSet.class);
when(rs.getString(eq("foo"))).thenReturn("This is mocked value");

PreparedStatement stmt = mock(PreparedStatement.class);
when(stmt.getResultSet()).thenReturn(rs);
when(stmt.execute()).thenReturn(true);

Connection connection = mock(Connection.class);
when(connection.prepareStatement(anyString(), anyInt(), anyInt()))
.thenReturn(stmt);

PowerMockito.mockStatic(SqlConnectionUtil.class);
PowerMockito.when(SqlConnectionUtil.getDbConnection(anyString(), anyString()))
.thenReturn(connection);

Map<String, String> sqlParams = new HashMap<>();
sqlParams.put("param1", "value1");
RccSqlParameterMap paramMap = mock(RccSqlParameterMap.class);
when(paramMap.getSqlParameters()).thenReturn(sqlParams);

PowerMockito.mockStatic(RccSqlParameterMap.class);
PowerMockito.when(RccSqlParameterMap.getParameterMap()).thenReturn(paramMap);

ResultSet actual = QueryRunner.getResultSetFromSql("SELECT ...",
"tenant", "product");
assertEquals(rs, actual);
assertEquals("This is mocked value", actual.getString("foo"));
}

}

Also, some general advices:

  1. Always use {} in each if-else statements even if they are one-lined. This will be much more convenient to merge and support your code in the future.
  2. Override your code to manage database connections properly. They should be closed! Use some third-party connection pooling mechanism like Apache DBCP

Hope it helps!

How to mock ResultSet.next() method using Mockito

You can chain doReturn() method calls:

doReturn(true).doReturn(true).doReturn(false).when(rs).next();

Or, as mentioned in the comments, chain thenReturn method calls:

when(rs.next()).thenReturn(true).thenReturn(true).thenReturn(false);

Or, if you want to take things even further, you can use Mockito Answers:

when(rs.next()).thenAnswer(new Answer() {
private int iterations = 2;

Object answer(InvocationOnMock invocation) {
return iterations-- > 0;
}
});

Mock ResultSet with Mockito

To be able to mock the ResultSet you should mock all objects that allow to create it that is Connection that creates the PreparedStatement, that itself creates the ResultSet.
Mocking the Connection will work in the tested code only if you provide a way to set the connection from the client code.

Here conn that is the Connection should be first injected as a dependency in your test fixture :

pstmt = conn.prepareStatement(strQuery.toString());

Generally you create a Connection such as :

conn = DriverManager.getConnection(DB_URL,USER,PASS);

or via a DataSource such as :

conn = ds.getConnection();

So you should abstract this part into an interface or a not final class and define an implementation that do this processing.
In this way you can mock the part that creates a Connection. And so you can mock the whole chain : Connection-PreparedStatement-ResultSet.


Personally I would avoid this way because mocking too many things is often not the right choice.

In your case, what you need is mocking the ResultSet to test the post processing after loading the ResultSet :

while(rs.next()) { 
ilCounter++;
ObjVoBean voObj = new ObjVoBean();
voObj.setLoc(rs.getString(1));
voObj.setDept(rs.getString(2));
voObj.setDeptDesc(rs.getString(3));
}

So as alternative you could move all code performed before in a method of specific class handling the persistence part. In this way you just need to mock this dependency and this method. You don't need to worry about Connection and any JDBC detail.

EmployeeDAO employeeDAO; // dependency to mock

// constructor with dependency
public Example(EmployeeDAO employeeDAO){
this.employeeDAO = employeeDAO;
}

private Employee method1(String str) {
ResultSet resultSet = employeeDAO.load(str);

if(null != rs) {
while(rs.next()) {
ilCounter++;
ObjVoBean voObj = new ObjVoBean();
voObj.setLoc(rs.getString(1));
voObj.setDept(rs.getString(2));
voObj.setDeptDesc(rs.getString(3));
}
.................
}
}

Of couse the DAO components also have to be unitary tested.

Bu as said earlier, asserting that a Connection is created or that it returns a PreparedStatement does not bring value. While testing that your queries perform what you expect from them is much more interesting in terms of functional coverage.

In this case, you want to test it against an in-memory DB such as H2 because unit tests are not integration tests and unit tests have to be fast executed.

To write DAO/Repository tests, Dbunit and DbSetup are good candidates because they provide facilities to setup the DB before each test (mainly injecting data and clearing data).

Unit testing a method that takes a ResultSet as parameter

You could simply mock your ResultSet to provide a value for each field and check that the result contains what you expect.

For example with Mockito, your test would be something like this:

@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {

@Mock
private ResultSet resultSet;

@Test
public void testConvert() throws SQLException {
// Define the behavior of the mock for each getString method's call
Mockito.when(resultSet.getString("id")).thenReturn("myId");
Mockito.when(resultSet.getString("sysname")).thenReturn("myHost");
Mockito.when(resultSet.getString("zos")).thenReturn("myOS");
Mockito.when(resultSet.getString("customer_name")).thenReturn("myCustomerName");

// Launch the method against your mock
SomeClass someClass = new SomeClass();
CItem item = someClass.convert(resultSet);

// Check the result
Assert.assertNotNull(item);
Assert.assertEquals("myId", item.getHinumber());
Assert.assertEquals("myHost", item.getHostname());
Assert.assertEquals("myOS", item.getOs());
Assert.assertEquals("myCustomerName", item.getTenant());
}
}

Easy way to fill up ResultSet with data

DBUnit doesn't present a result set, to my knowledge, although it will well help you populate your in memory database.

I would say that a mocking framework is the wrong approach at this point. Mocking is about testing behavior and interaction, not just returning data, so it will likely get in your way.

I would instead either implement a result set interface, or create a dynamic proxy of a result set interface to a class that implements the methods you care about without having to implement the whole result set. You will likely find maintaining a class as easy as maintaining an in memory database (provided that the dataset under test is consistent), and probably easier to debug.

You could back up that class with DBUnit, where you take a snapshot of your result set with dbunit, and have dbunit read it back during the test from xml, and have your dummy result set read the data from dbunit's classes. This would be a reasonable approach if the data was mildly complex.

I would go for the in memory database if the classes were so coupled that they need to read data that was modified as part of the same test. Even then, I would consider using a copy of the real database until you managed to pull that dependency apart.

A simple proxy generation method:

private static class SimpleInvocationHandler implements InvocationHandler {
private Object invokee;

public SimpleInvocationHandler(Object invokee) {
this.invokee = invokee;
}

public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
method = invokee.getClass().getMethod(method.getName(), method.getParameterTypes());
if (!method.isAccessible()) {
method.setAccessible(true);
}
try {
return method.invoke(invokee, args);
} catch (InvocationTargetException e) {
throw e.getTargetException();
}
}
}

public static <T> T generateProxy(Object realObject, Class... interfaces) {
return (T) Proxy.newProxyInstance(realObject.getClass().getClassLoader(), interfaces, new SimpleInvocationHandler(realObject));
}

how to mock resultmetadata for junit testing

Here is an example of what you need to do:

import org.mockito.Mockito;

import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.SQLException;

import static org.junit.Assert.assertEquals;
import static org.mockito.ArgumentMatchers.eq;
import static org.mockito.Mockito.when;

public class Test {


@org.junit.Test
public void test() throws SQLException {

// prepare the dependant mock
ResultSetMetaData rsMetaMock = Mockito.mock(ResultSetMetaData.class);
when(rsMetaMock.getColumnName(eq(1))).thenReturn("something");

// prepare main mock for result set and define when
// main mock to return dependant mock
ResultSet rs = Mockito.mock(ResultSet.class);
when(rs.getMetaData()).thenReturn(rsMetaMock);

// application logic
ResultSetMetaData rsmd = rs.getMetaData();

//assertions
assertEquals(rsmd.getColumnName(1), "something");
}
}

How to deal with Page while unit testing with mockito and Junit

You can mock the Page object also if there is a aneed to handle some other functionality inside your service class. Assuming that your service class is actually something like:

public class MyService {
@Resource
private SampleRepository repo;

public Page<SampleDto> findAllSample() {
var sampleData = repo.findAllSample();
// perhaps some operations with sample data and page
return sampleData;
}
}

then the test class could be something like (JUnit4):

@RunWith(MockitoJUnitRunner.class)
public class MySampleTest {
@Mock
private SampleRepository repo;
@Mock
private Page<SampleDto> page;
@InjectMocks
private MyService myService;

@Test
public void test() {
doReturn(page).when(repo).findAll();
var listSampleDtos = List.of(new SampleDto()); // populate with what you need
doReturn(listSampleDtos).when(page).getContent();
var page = myService.findAllSample();
// ... do the asserts, just as an example:
verify(repo).findAll(); // called
assertEquals(1, page.getContent().size());
}


Related Topics



Leave a reply



Submit