如何模拟结果集并使用Java中的Mockito填充它

Tej*_*hah 35 java junit4 mockito

我有代码,我填充ResultsetCallableStatement.executeQuery().我已经嘲笑了ResultSet,CallableStatement但为了测试我必须填充的方法ResultSet.

这是我正在测试的方法的代码

ResultSet rset = cs.executeQuery();
while (rset.next()) {
IndexVolatilityImpl tsImpl = new IndexVolatilityImpl();
tsImpl.setTradeDate(rset.getString("trade_date"));
tsImpl.setTradeTime(rset.getString("trade_time"));
tsImpl.setExprDate(rset.getString("expr_date"));
tsImpl.setSymbol(rset.getString("symbol"));
tsImpl.setTradePrice(rset.getDouble("trade_price"));
tsImpl.setContractMonth(rset.getString("contract_month"));
tsImpl.setMilliSecs(rset.getString("trade_time_thou"));
colIndexVolatilityImpl.add(tsImpl);
Run Code Online (Sandbox Code Playgroud)

我已经嘲笑了CallableStatement和ResultSet,因为他们被嘲笑我的rset是空的.我想填充Resultset并按如下方式执行

resultSetMock = Mockito.mock(ResultSet.class);
Mockito.when(resultSetMock.getString("trade_date")).thenReturn("03/10/2011");
Mockito.when(resultSetMock.getString("trade_time")).thenReturn("12:24:56");
Mockito.when(resultSetMock.getString("expr_date")).thenReturn("03/19/2011");
Mockito.when(resultSetMock.getString("symbol")).thenReturn("VIX1");
Mockito.when(resultSetMock.getDouble("trade_price")).thenReturn(Double.valueOf("20.96"));
Mockito.when(resultSetMock.getString("contract_month")).thenReturn("1");
Mockito.when(resultSetMock.getString("trade_time_thou")).thenReturn("165");

Mockito.doReturn(resultSetMock).when(callableStatementMock).executeQuery();
Run Code Online (Sandbox Code Playgroud)

不过rsetnull.

pro*_*tif 43

您还应该模拟该next()方法,以便在第一次调用时返回true,因为mockito将false默认返回.

Mockito.when(resultSetMock.next()).thenReturn(true).thenReturn(false);
Run Code Online (Sandbox Code Playgroud)

  • 我这样做但我想填充ResultSet,我正如上所述,但它出现了null.你能否解释我做错了什么? (2认同)

And*_*own 11

从提出这个问题起 10 年后,您很有可能会使用 Spring Boot 2+ 和 h2 作为内存数据库进行测试。如果是这种情况,那么您可以使用该类从 CSV 数据org.h2.tools.Csv创建一个实现:ResultSet

import org.h2.tools.Csv;
Run Code Online (Sandbox Code Playgroud)
// mock resultset

String csvResults =
    "0001, John Doe\n" +
    "0002, Bob Smith\n" +
    "0003, Alice Doe\n";

ResultSet rs = new Csv().read(new StringReader(csvResults), new String[] {"id", "name"});
Run Code Online (Sandbox Code Playgroud)

ResultSet然后以任何你想要的方式使用它。这是一个 Mockito 示例,它将它作为RowCallbackHandler调用提供JdbcTemplate query()

JdbcTemplate mockTemplate = mock(JdbcTemplate.class);

doAnswer(ia -> {
  while (rs.next()) {
    ia.getArgument(2, RowCallbackHandler.class).processRow(rs);
  }
  return null;
}).when(mockTemplate).query(any(String.class), any(SqlParameterSource.class), any(RowCallbackHandler.class));

// change the above when() args to match how you are using JdbcTemplate
Run Code Online (Sandbox Code Playgroud)


kar*_*k m 7

我为同样的案子写过一些东西.您可以使用Mockito模拟结果集.您也可以通过使用这段代码模拟resultset.next()来循环遍历结果集的模拟行.

// two dimensional array mocking the rows of database.
String[][] result = { { "column1", "column2" }, { "column1", "column2" } };

@InjectMocks
@Spy
private TestableClass testableClass;

@Mock
private Connection connection;

@Mock
private Statement statement;

@Mock
private ResultSet resultSet;

@BeforeTest
public void beforeTest() {
    MockitoAnnotations.initMocks(this);
}

@BeforeMethod
public void beforeMethod() throws SQLException {
    doAnswer(new Answer<Connection>() {
        public Connection answer(InvocationOnMock invocation)
                throws Throwable {
            return connection;

        }
    }).when(testableClass).getConnection();

    when(connection.createStatement()).thenReturn(statement);
    when(statement.executeQuery(anyString())).thenReturn(resultSet);
    final AtomicInteger idx = new AtomicInteger(0);
    final MockRow row = new MockRow();

    doAnswer(new Answer<Boolean>() {

        @Override
        public Boolean answer(InvocationOnMock invocation) throws Throwable {
            int index = idx.getAndIncrement();
            if (result.length <= index) {
                return false;
            } 
            String[] current = result[index];
            row.setCurrentRowData(current);
            return true;

        }

        ;
    }).when(resultSet).next();

    doAnswer(new Answer<String>() {

        @Override
        public String answer(InvocationOnMock invocation) throws Throwable {
            Object[] args = invocation.getArguments();
            int idx = ((Integer) args[0]).intValue();
            return row.getColumn(idx);
        }

        ;
    }).when(resultSet).getString(anyInt());
}

static class MockRow {
    String[] rowData;

    public void setCurrentRowData(String[] rowData) {
        this.rowData = rowData;
    }

    public String getColumn(int idx) {
        return rowData[idx - 1];
    }
}
Run Code Online (Sandbox Code Playgroud)


Ale*_*äll 6

我稍微重写了@karthik m 的回答,以使 ResultSet 模拟程序独立:

通过使用下面的类,我可以轻松地将查询结果导出为 csv 并围绕它编写一个测试。

并非 ResultSet 中的所有方法都被模拟,因为我不需要它们,但这些方法使用起来应该相当简单。

import no.di.common.util.StringUtil;
import org.apache.commons.io.FileUtils;
import org.apache.commons.io.LineIterator;
import org.mockito.invocation.InvocationOnMock;
import org.mockito.stubbing.Answer;

import java.io.File;
import java.io.IOException;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

import static org.mockito.Matchers.anyInt;
import static org.mockito.Matchers.anyString;
import static org.mockito.Mockito.doAnswer;
import static org.mockito.Mockito.mock;

/**
 * Creates a Mock of a ResultSet
 */
public class ResultSetMocker {

    private Map<String, Integer> columnNames = new HashMap<>();

    private Object[][] result;

    public ResultSetMocker(String filename) throws IOException {
        loadData(filename);
    }

    private void loadData(String filename) throws IOException {
        List<Object[]> toRet = new ArrayList<>();

        int numberOfParts = 0;
        LineIterator it = FileUtils.lineIterator(new File(filename), "ISO8859-1");
        try {
            String names = it.nextLine();
            String[] name = names.split(";");
            for(int i = 0; i < name.length; i++) {
                columnNames.put(name[i], i + 1);
            }

            while (it.hasNext()) {
                String line = it.nextLine();

                String[] parts = line.split(";");
                numberOfParts = parts.length;
                Object[] result = new Object[parts.length];
                for(int i = 0; i < parts.length; i++) {
                    if(parts[i].equals("(null)"))
                        result[i] = null;
                    else if(StringUtil.isAllNumeric(parts[i]))
                        result[i] = Integer.parseInt(parts[i]);
                    else
                        result[i] = parts[i];
                }

                toRet.add(result);
            }
        } finally {
            it.close();
        }

        result = toRet.toArray(new Object[toRet.size()][numberOfParts]);
    }

    public ResultSet getResultSet() throws SQLException, IOException {
        ResultSet resultSet = mock(ResultSet.class);

        final AtomicInteger idx = new AtomicInteger(0);
        final MockRow row = new MockRow(columnNames);

        doAnswer(new Answer<Boolean>() {
            @Override
            public Boolean answer(InvocationOnMock invocation) throws Throwable {
                int index = idx.getAndIncrement();
                if (result.length > index) {
                    row.setCurrentRowData(result[index]);
                    return true;
                } else
                    return false;
            }
        }).when(resultSet).next();

        doAnswer(new Answer<String>() {
            @Override
            public String answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                int idx = (Integer) args[0];
                return row.getString(idx);
            }
        }).when(resultSet).getString(anyInt());

        doAnswer(new Answer<String>() {
            @Override
            public String answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getString(name);
            }
        }).when(resultSet).getString(anyString());

        doAnswer(new Answer<Object>() {
            @Override
            public Object answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getObject(name);
            }
        }).when(resultSet).getObject(anyString());

        doAnswer(new Answer<Integer>() {
            @Override
            public Integer answer(InvocationOnMock invocation) throws Throwable {
                Object[] args = invocation.getArguments();
                String name = (String) args[0];
                return row.getInt(name);
            }
        }).when(resultSet).getInt(anyString());

        return resultSet;
    }

    static class MockRow {
        Object[] rowData;
        private Map<String, Integer> columnNames;

        public MockRow(Map<String, Integer> columnNames) {

            this.columnNames = columnNames;
        }

        public void setCurrentRowData(Object[] rowData) {
            this.rowData = rowData;
        }

        public String getString(int idx) {
            return (String)rowData[idx - 1];
        }

        public String getString(String name) {
            return (String)rowData[columnNames.get(name) - 1];
        }

        public Object getObject(String name) {
            return rowData[columnNames.get(name) - 1];
        }

        public Integer getInt(String name) {
            return (Integer)rowData[columnNames.get(name) - 1];
        }
    }
}
Run Code Online (Sandbox Code Playgroud)