'Mock ResultSet with Mockito

How to mock the resultset?

In the test class trying to mock the resultset as below but, when trying to test getting error as UnnecessaryStubbingException at statements :

voObj.setDept(rs.getString(2)); 

and

voObj.setDeptDesc(rs.getString(3));

Any suggessions on how to mock the resultset?

public class Example { 
    public static void main(String[] s) {
        method1();
        method2();
        ..........
    }

    private Employee method1(String str) {
                Connection conn           =  getConnection();   
        PreparedStatement pstmt   = null;
        .........
        pstmt = conn.prepareStatement(strQuery.toString());
        rs  = pstmt.executeQuery();
        int ilCounter   = 0; 
        int maxId   = method2(loc); //some DB calls here with select

        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));
            }
            .................
        }
       }

   private Employee method2(String str1) {
                Connection connOHM      = getConnection();  
        PreparedStatement pstmt     = null;
        .........
       //some DB call with select ...
   }
}

public class ExampleTest { 
   @InjectMocks
   Example example;

   @Mock
   private Connection c;

   @Mock
   private PreparedStatement preStmt;
    .....

   @Before
   public void setUp() {
        ........
   }

   @Test
   public void testMethod1() throws SQLException {
        ResultSet resultSetMock = Mockito.mock(ResultSet.class);
        when(resultSetMock.getString(1)).thenReturn("1111");
        when(resultSetMock.getString(2)).thenReturn("2222");
        when(resultSetMock.getString(3)).thenReturn("dept desc");

        when(c.prepareStatement(any(String.class))).thenReturn(preStmt);
        when(resultSetMock.next()).thenReturn(true).thenReturn(false); 
        doReturn(resultSetMock).when(preStmt).executeQuery();

        example.method1("1111");            
        assertTrue(true);
   }
}


Solution 1:[1]

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).

Solution 2:[2]

This is a mock Result Set I ripped off of GitHub

/*
* Distributed under the terms of the MIT License.
* Copyright (c) 2009, Marcelo Criscuolo.
*/

package commondb.mock;

import java.io.InputStream;
import java.io.Reader;
import java.io.StringReader;
import java.math.BigDecimal;
import java.net.URL;
import java.sql.Array;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Date;
import java.sql.NClob;
import java.sql.Ref;
import java.sql.ResultSet;
import java.sql.ResultSetMetaData;
import java.sql.RowId;
import java.sql.SQLException;
import java.sql.SQLWarning;
import java.sql.SQLXML;
import java.sql.Statement;
import java.sql.Time;
import java.sql.Timestamp;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.Calendar;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

import org.apache.commons.lang.StringUtils;


public class MockResultSet implements ResultSet {
    static final String INVALID_COLUMN_NAME = "invalid column name";
    static final String INVALID_COLUMN_INDEX = "invalid column index";
        static final DateFormat DATE_ISO_8601 = new SimpleDateFormat("yyyy-MM-dd");
    private List<String[]> rowset = new ArrayList<String[]>();
    private int cursor = -1;
    private Map<String, Integer> columnMap = new HashMap<String, Integer>();
    private CSVLineSplitter splitter = new CSVLineSplitter();

    public MockResultSet() {
    }

    /**
     * ResultSet rs = new MockResultSet(
     *     "ID,NAME,CITY",
     *     "3,John,New York",
     *     "4,Bill,Sydney"
     * );
     *
     * @param str headers and rows that form the CSV data
     */
    public MockResultSet(String... str) throws SQLException {
        loadCSV(new StringReader(StringUtils.join(str, "\n")));
    }
    
    /**
     * @param in source from where the CSV data will be read
     * 
     * @throws SQLException any exception will be wrapped
     * on SQLException, so that it is not necessary to
     * add additional catches to client code.
     */
    public MockResultSet(Readable in) throws SQLException {
        loadCSV(in);
    }
    
    public void loadCSV(Readable in) throws SQLException {
        final Scanner sc = new Scanner(in);
        
        if (!sc.hasNextLine()) {
            sc.close();
            throw new SQLException("empty data source");
        }

        
        // load column headers
        String line = sc.nextLine();
        int index = 1;
        for (String column : splitter.split(line)) {
            columnMap.put(column, index);
            index++;
        }
        
        
        // load data
        while (sc.hasNextLine()) {
            line = sc.nextLine();
            
            String[] row = splitter.split(line);
            rowset.add(row);
        }
        
        sc.close();
    }
    
    @Override
    public boolean absolute(int row) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void afterLast() throws SQLException {
        cursor = rowset.size();
    }

    @Override
    public void beforeFirst() throws SQLException {
        cursor = -1;
    }

    @Override
    public void cancelRowUpdates() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void clearWarnings() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void close() throws SQLException {
        // noop
    }

    @Override
    public void deleteRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int findColumn(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean first() throws SQLException {
        if (rowset.size() > 0) {
            cursor = 0;
            return true;
        }
        
        return false;
    }

    @Override
    public Array getArray(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Array getArray(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public InputStream getAsciiStream(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public InputStream getAsciiStream(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public BigDecimal getBigDecimal(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public BigDecimal getBigDecimal(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    @Deprecated
    public BigDecimal getBigDecimal(int columnIndex, int scale)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    @Deprecated
    public BigDecimal getBigDecimal(String columnLabel, int scale)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public InputStream getBinaryStream(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public InputStream getBinaryStream(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Blob getBlob(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Blob getBlob(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean getBoolean(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean getBoolean(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public byte getByte(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public byte getByte(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public byte[] getBytes(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public byte[] getBytes(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Reader getCharacterStream(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Reader getCharacterStream(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Clob getClob(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Clob getClob(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getConcurrency() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public String getCursorName() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
        /**
         * Dates are expected to be formatted as yyyy-MM-dd.
         * See http://en.wikipedia.org/wiki/ISO_8601#Calendar_dates
         */
    public Date getDate(int columnIndex) throws SQLException {
        try {
            String value = getValue(columnIndex);
            Date date = null;
            if ( (value != null) && (value.trim().length() >= 0)) {
                date = new Date(DATE_ISO_8601.parse(value).getTime());
            }
            
            return date;
        } catch (Exception e) {
            throw new SQLException(e);
        }
    }

    @Override
    public Date getDate(String columnLabel) throws SQLException {
        return getDate(getColumnIndex(columnLabel));
    }

    @Override
    public Date getDate(int columnIndex, Calendar cal) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Date getDate(String columnLabel, Calendar cal) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public double getDouble(int columnIndex) throws SQLException {
        try {
            String value = getValue(columnIndex);
            if ( (value == null) || (value.trim().length() == 0)) {
                value = "0";
            }
            
            value = value.replace(',', '.');
            
            return Double.parseDouble(value);
        } catch (Exception e) {
            throw new SQLException(e);
        }
    }

    @Override
    public double getDouble(String columnLabel) throws SQLException {
        return getDouble(getColumnIndex(columnLabel));
    }

    @Override
    public int getFetchDirection() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getFetchSize() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public float getFloat(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public float getFloat(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getHoldability() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getInt(int columnIndex) throws SQLException {
        try {
            String value = getValue(columnIndex);
            if ( (value == null) || (value.trim().length() == 0)) {
                value = "0";
            }

            return Integer.parseInt(value);
        } catch (Exception e) {
            throw new SQLException(e);
        }
    }

    @Override
    public int getInt(String columnLabel) throws SQLException {
        return getInt(getColumnIndex(columnLabel));
    }

    @Override
    public long getLong(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public long getLong(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public ResultSetMetaData getMetaData() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Reader getNCharacterStream(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Reader getNCharacterStream(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public NClob getNClob(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public NClob getNClob(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public String getNString(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public String getNString(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Object getObject(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Object getObject(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Object getObject(int columnIndex, Map<String, Class<?>> map)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Object getObject(String columnLabel, Map<String, Class<?>> map)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public <T> T getObject(int columnIndex, Class<T> type) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public <T> T getObject(String columnLabel, Class<T> type) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Ref getRef(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Ref getRef(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public RowId getRowId(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public RowId getRowId(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public SQLXML getSQLXML(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public SQLXML getSQLXML(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public short getShort(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public short getShort(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Statement getStatement() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public String getString(int columnIndex) throws SQLException {
        return getValue(columnIndex);
    }

    private String getValue(int columnIndex) throws SQLException {
        if ( (cursor < 0) || (cursor >= rowset.size()) ) {
            throw new SQLException("cursor not pointing to a valid row");
        }
        
        String[] row = rowset.get(cursor);
        if ( (columnIndex < 0) || (columnIndex > row.length) ) {
            throw new SQLException(INVALID_COLUMN_INDEX);
        }
        
        return row[columnIndex - 1];
    }

    @Override
    public String getString(String columnLabel) throws SQLException {
        return getString(getColumnIndex(columnLabel));
    }

    private Integer getColumnIndex(String columnLabel) throws SQLException {
        Integer index = columnMap.get(columnLabel);
        if (index == null) {
            throw new SQLException(INVALID_COLUMN_NAME);
        }
        return index;
    }

    @Override
    public Time getTime(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Time getTime(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Time getTime(int columnIndex, Calendar cal) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Time getTime(String columnLabel, Calendar cal) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Timestamp getTimestamp(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Timestamp getTimestamp(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Timestamp getTimestamp(int columnIndex, Calendar cal)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public Timestamp getTimestamp(String columnLabel, Calendar cal)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public int getType() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public URL getURL(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public URL getURL(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    @Deprecated
    public InputStream getUnicodeStream(int columnIndex) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    @Deprecated
    public InputStream getUnicodeStream(String columnLabel) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public SQLWarning getWarnings() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void insertRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean isAfterLast() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean isBeforeFirst() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean isClosed() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean isFirst() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean isLast() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean last() throws SQLException {
        if (rowset.size() > 0) {
            cursor = rowset.size() - 1;
            return true;
        }
        
        return false;
    }

    @Override
    public void moveToCurrentRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void moveToInsertRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean next() throws SQLException {
        
        final boolean hasNext = (cursor + 1) < rowset.size();
        if (hasNext) {
            cursor++;
        }
        
        return hasNext;
    }

    @Override
    public boolean previous() throws SQLException {
        cursor--;
        
        if (cursor < -1) { 
            cursor = -1; // one row before the first is the limit
        }
        
        final boolean beforeFirst = (cursor < 0);       
        return !beforeFirst;
    }

    @Override
    public void refreshRow() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean relative(int rows) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean rowDeleted() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean rowInserted() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public boolean rowUpdated() throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void setFetchDirection(int direction) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void setFetchSize(int rows) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateArray(int columnIndex, Array x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateArray(String columnLabel, Array x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(int columnIndex, InputStream x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(String columnLabel, InputStream x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(int columnIndex, InputStream x, int length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(String columnLabel, InputStream x, int length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(int columnIndex, InputStream x, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateAsciiStream(String columnLabel, InputStream x, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBigDecimal(int columnIndex, BigDecimal x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBigDecimal(String columnLabel, BigDecimal x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(int columnIndex, InputStream x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(String columnLabel, InputStream x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(int columnIndex, InputStream x, int length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(String columnLabel, InputStream x, int length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(int columnIndex, InputStream x, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBinaryStream(String columnLabel, InputStream x,
            long length) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(int columnIndex, Blob x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(String columnLabel, Blob x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(int columnIndex, InputStream inputStream)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(String columnLabel, InputStream inputStream)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(int columnIndex, InputStream inputStream, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBlob(String columnLabel, InputStream inputStream,
            long length) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBoolean(int columnIndex, boolean x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBoolean(String columnLabel, boolean x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateByte(int columnIndex, byte x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateByte(String columnLabel, byte x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBytes(int columnIndex, byte[] x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateBytes(String columnLabel, byte[] x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(int columnIndex, Reader x)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(String columnLabel, Reader reader)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(int columnIndex, Reader x, int length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(String columnLabel, Reader reader,
            int length) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(int columnIndex, Reader x, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateCharacterStream(String columnLabel, Reader reader,
            long length) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(int columnIndex, Clob x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(String columnLabel, Clob x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(int columnIndex, Reader reader) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(String columnLabel, Reader reader)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(int columnIndex, Reader reader, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateClob(String columnLabel, Reader reader, long length)
            throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateDate(int columnIndex, Date x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateDate(String columnLabel, Date x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateDouble(int columnIndex, double x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    @Override
    public void updateDouble(String columnLabel, double x) throws SQLException {
        throw new UnsupportedOperationException("to be implemented");
    }

    

    

    

}

Solution 3:[3]

I also wanted to be able to mock a ResultSet with multiple rows and found various answers online but none of them seemed to meet my needs.

In my case I have a class method (SUT) that iterates through a(n) (unknown) number of rows and perform some logic on them (in production runtime). I am trying to ensure that the correct objects that get built from these rows are returned. At test time I know the exact number of rows I am going to examine.

My solution was to @InjectMocks into my my repo class which takes a "factory" connection class that provides the connection via the repo constructor. This is what I did:

import static org.mockito.Mockito.*;

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

import com.SomeStuff.MyRepository;
import com.SomeStuff.MyConnectionFactory;
import com.SomeStuff.Widget;
import org.junit.jupiter.api.BeforeEach;
import org.mockito.*;
import static org.junit.jupiter.api.Assertions.*;
import java.util.List;
import lombok.SneakyThrows;
import org.junit.jupiter.api.Test;

public class MyClass {
    @InjectMocks
    private MyRepository myRepository;

    @Mock
    private MyConnectionFactory mcf;

    @Mock
    private Connection c;

    @Mock
    private PreparedStatement stmt;

    @Mock
    private ResultSet rs;

    // snipped code below, more to follow
}

then I added a @BeforeEeach to my setup method and inside there comes the secret sauce. In my case I know my code in the SUT wants to iterate through 9 fake rows and I also know that in a couple of cases it only need to work with two rows if they meet certain characteristics.

public class MyClass {        
        // snipped the previous stuff above
    
        MockitoAnnotations.openMocks(this);
    
        when(mcf.getConnection()).thenReturn(c);
        when(c.prepareStatement(any(String.class))).thenReturn(stmt);

        when(rs.next())
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(true)
            .thenReturn(false);
    
        when(rs.getInt("person_id"))
            .thenReturn(10001)
            .thenReturn(10001)
            .thenReturn(10001)
            .thenReturn(10001)
            .thenReturn(10001)
            .thenReturn(10002)
            .thenReturn(10002)
            .thenReturn(10002)
            .thenReturn(10002);
    
        when(rs.getString("first_name"))
            .thenReturn("John")
            .thenReturn("Dave");
    
        when(rs.getString("last_name"))
            .thenReturn("Doe")
            .thenReturn("Smith");
    
        when(rs.getString("key_value"))
            .thenReturn("Yes")
            .thenReturn("")
            .thenReturn("8005551212")
            .thenReturn("Hello,")
            .thenReturn("No")
            .thenReturn("")
            .thenReturn("")
            .thenReturn("World!")
            .thenReturn("No");
    
        when(stmt.executeQuery()).thenReturn(rs);
    }

Take note that in the above code there is an additional .thenReturn(false) for next or it will never be false. This will cause an infiinte loop if you are while-ing through the rows.

Also notice that in my case my SUT only calls into first_name and last_name twice (as mentioned above, due to other criteria in the rows) so I call thenReturn on it twice (or else there would be 8 calls to it and that won't suit my needs.

Finally I test it like this:

public class MyClass {
// Everything snipped above

    @Test
    @SneakyThrows
    public void getPeople_correct_number_of_Person_is_retrieved() {
        List<Person> people = myRepository.getPeople();
        assertEquals(1, people.size());
    }
}

In my case above I expect one Person to be returned where the 9 rows actually represented characteristics for two people.

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 Manav Patel
Solution 3