2011-06-07 66 views
22

我有代码在其中使用CallableStatement.executeQuery()填充Resultset。我嘲笑了ResultSet和CallableStatement,但为了测试我必须填充ResultSet的方法。如何模拟结果集并使用Java中的Mockito填充它

这里是从方法我测试

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(); 

但是结果集签出为空。

因此,任何帮助将不胜感激,以帮助如何填充模拟结果集。

感谢 Tejas的

+0

最好的答案是在底部,并拥有超过24 upvotes通过@proactif – nanospeck 2017-06-23 05:26:08

回答

27

你也应该嘲笑next()方法将它返回true,第一次这就是所谓的,因为会的Mockito默认情况下返回false。

Mockito.when(resultSetMock.next()).thenReturn(true).thenReturn(false); 
+2

我这样做,但我想填充ResultSet和我做如上文所述,但它出来为空。你能否说清楚我做错了什么? – 2011-06-07 16:50:15

+0

刚刚尝试过类似的测试代码,它的工作。所以你的rset是空的?我猜cs对象当然是callableStatementMock,在这种情况下它应该可以工作。我认为你的问题只是你的RS是空的,但我不知道它是如何可以为空。 – proactif 2011-06-07 17:40:54

4

我写了一些东西给这个相同的情况。你可以使用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]; 
    } 
} 
+0

你为什么做MockRow类? – 2014-11-27 07:43:33

+0

@UmerHayat - 它是对数组表示的干净封装。 – 2014-12-12 01:00:16

2

我改写@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]; 
     } 
    } 
}