Resultset
にCallableStatement.executeQuery()
を入力するコードがあります。私はResultSet
とCallableStatement
をm笑しましたが、メソッドをテストするために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);
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();
ただし、rset
はnull
です。
Mockitoはデフォルトでfalse
を返すため、next()
メソッドをモックして、最初に呼び出されたときにtrueを返すようにする必要があります。
Mockito.when(resultSetMock.next()).thenReturn(true).thenReturn(false);
私はこの同じケースのために何かを書きました。 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];
}
}
ResultSetモッカーをスタンドアロンにするために、@ karthik mの回答を少し書き直しました。
以下のクラスを使用することで、クエリの結果を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];
}
}
}
ここでのゲームに少し遅れましたが、元のモックに必要なのはこれだけだったようです...
Mockito.when(resultSetMock.next()).thenReturn(true);
これは、マッパー-結果セットのマッピングに使用しているものが結果セットにデータがあることを知るために必要です。