java - 使用 Mockito 模拟结果集
问题描述
如何模拟结果集?
在测试类中尝试如下模拟结果集,但是,当尝试测试UnnecessaryStubbingException
在语句中出现错误时:
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);
}
}
解决方案
为了能够模拟ResultSet
你应该模拟所有允许创建它的对象,即创建它Connection
,PreparedStatement
它本身创建ResultSet
。仅当您提供一种从客户端代码设置连接的方法时,模拟连接才会在测试代码中起作用。
这conn
是 Connection 应该首先作为依赖项注入到您的测试夹具中:
pstmt = conn.prepareStatement(strQuery.toString());
通常,您创建一个Connection
例如:
conn = DriverManager.getConnection(DB_URL,USER,PASS);
或通过DataSource
诸如:
conn = ds.getConnection();
因此,您应该将此部分抽象为接口或非最终类,并定义执行此处理的实现。通过这种方式,您可以模拟创建连接的部分。所以你可以模拟整个链:Connection-PreparedStatement-ResultSet。
我个人会避免这种方式,因为嘲笑太多东西通常不是正确的选择。
在您的情况下,您需要在加载 ResultSet 后模拟 ResultSet 以测试后处理:
while(rs.next()) {
ilCounter++;
ObjVoBean voObj = new ObjVoBean();
voObj.setLoc(rs.getString(1));
voObj.setDept(rs.getString(2));
voObj.setDeptDesc(rs.getString(3));
}
因此,作为替代方案,您可以将之前执行的所有代码移动到处理持久性部分的特定类的方法中。这样你只需要模拟这个依赖和这个方法。您无需担心 Connection 和任何 JDBC 细节。
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));
}
.................
}
}
当然,DAO 组件也必须进行单一测试。
Bu 如前所述,断言 aConnection
已创建或它返回 aPreparedStatement
不会带来价值。在功能覆盖方面测试您的查询是否执行您对它们的期望时会更有趣。
在这种情况下,您希望针对 H2 等内存数据库对其进行测试,因为单元测试不是集成测试,并且必须快速执行单元测试。
要编写 DAO/Repository 测试,Dbunit和DbSetup是很好的候选者,因为它们提供了在每次测试之前设置 DB 的工具(主要是注入数据和清除数据)。
推荐阅读
- javascript - 在 Javascript 中,如何从下拉列表和表单中汇总数组中的所有值?
- function - 如何在 Dart 中转发函数参数
- c# - What is the purpose of a dropdown menu when the selections' value and text are different?
- java - 同步线程一个简单的产生reduce问题我看不懂。为什么同步块内的 Thread.sleep 使它工作不同?
- azure-devops - 带有 SonarCloud 的 Azure DevOps 找不到测试
- css - 不同div中的第一段大小不同
- javascript - 如何从网页上绘制/插入的形状和文本生成 HTML 和 CSS?
- javascript - Angular:HTML页面在从后端加载图像之前完成渲染
- c++ - 使用 librestc-cpp 编译:对 pthread_condattr_setclock 的未定义引用
- c# - VS Code Omnisharp.MsBuild.Projectmanager 无法加载程序集 System.Numerics.Vectors 4.1.3.0