如何模拟结果集?
在测试类中试图模拟如下的resultset但是,在试图测试时得到错误为UnnecessaryStubbingException
at语句:
voObj.setDept(rs.getString(2));
和
voObj.setDeptDesc(rs.getString(3));
有关于如何模拟结果集的建议吗?
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);
}
}
3条答案
按热度按时间ny6fqffe1#
为了能够模拟
ResultSet
,您应该模拟所有允许创建它的对象,即创建PreparedStatement
的Connection
,它本身创建ResultSet
。只有在您提供从客户端代码设置连接的方法时,模拟连接才能在测试代码中工作。这里,作为Connection的
conn
应该首先作为一个依赖项注入到您的测试装置中:通常您会建立
Connection
,例如:或者经由X1 M6 N1 X,例如:
所以你应该把这个部分抽象成一个接口或者一个非final类,然后定义一个实现来完成这个处理,这样你就可以模拟创建Connection的部分,这样你就可以模拟整个链:连接准备语句-结果集。
就我个人而言,我会避免这种方式,因为嘲笑太多的事情往往不是正确的选择。
在您的示例中,您需要模拟ResultSet以测试加载ResultSet后的后处理:
因此,作为替代方案,您可以将之前执行的所有代码移到处理持久性部分的特定类的方法中。这样,您只需要模拟此依赖关系和此方法。您不需要担心连接和任何JDBC细节。
当然,DAO组件也必须进行单元测试。
但是,正如前面所说,Assert创建了一个
Connection
或者它返回了一个PreparedStatement
并没有带来任何价值,而测试您的查询是否执行了您期望的功能,在功能覆盖方面要有趣得多。在这种情况下,您希望针对内存中的DB(如H2)进行测试,因为单元测试不是集成测试,并且单元测试必须快速执行。
要编写DAO/Repository测试,Dbunit和DbSetup是很好的候选对象,因为它们提供了在每次测试之前设置DB的工具(主要是注入数据和清除数据)。
j0pj023g2#
这是一个模拟的结果集,我从GitHub上撕下
rlcwz9us3#
我还希望能够模拟一个具有多行的结果集,并在网上找到了各种答案,但似乎没有一个能满足我的需要。
在我的例子中,我有一个类方法(SUT),它迭代(n)(未知)行,并对它们执行一些逻辑(在生产运行时)。我试图确保从这些行构建的正确对象被返回。在测试时,我知道我要检查的确切行数。
我的解决方案是将 @InjectMocks 插入到我的my repo类中,它接受一个“工厂”连接类,通过repo构造函数提供连接。我所做的是:
然后我在我的 setup 方法中添加了一个 @BeforeEeach,这里面就有了秘密的调味汁。在我的例子中,我知道SUT中的代码需要迭代9个伪行,而且我还知道在一些情况下,如果两行满足某些特征,它只需要处理这两行。
请注意,在上面的代码中,next 有一个额外的 .thenReturn(false),否则它永远不会为false。如果您 while-ing 遍历行,这将导致无限循环。
还要注意,在我的例子中,我的SUT只调用first_name和last_name两次(如上所述,由于行中的其他条件),所以我对它调用了两次 thenReturn(否则将有8次对它的调用,这将不符合我的需要。
最后我这样试验一下:
在我上面的例子中,我希望返回一个Person,其中9行实际上表示两个人的特征。