单元测试以 ResultSet 作为参数的方法
Unit testing a method that takes a ResultSet as parameter
如何对无法实例化的对象进行单元测试?因为目前我有一个将 ResultSet 转换为对象的方法,但我不确定这是否违反了任何编程原则。
public CItem convert(ResultSet rs) {
CItem ci = new CItem ();
try {
ci.setHinumber(rs.getString("id"));
ci.setHostname(rs.getString("sysname"));
ci.setOs(rs.getString("zos"));
ci.setTenant(rs.getString("customer_name"));
//ci.setInstallation(rs.getField("installation_name"));
} catch (SQLException e) {
e.printStackTrace();
}
return ci;
}
是否仅仅因为它无法进行单元测试,我就需要寻找其他方法来解决这个问题?或者我能以某种方式伪造一个 ResultSet 对象吗?
如有任何帮助,我们将不胜感激。
您可以简单地模拟您的 ResultSet
为每个字段提供一个值并检查结果是否包含您期望的内容。
例如 Mockito,你的测试应该是这样的:
@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
@Mock
private ResultSet resultSet;
@Test
public void testConvert() throws SQLException {
// Define the behavior of the mock for each getString method's call
Mockito.when(resultSet.getString("id")).thenReturn("myId");
Mockito.when(resultSet.getString("sysname")).thenReturn("myHost");
Mockito.when(resultSet.getString("zos")).thenReturn("myOS");
Mockito.when(resultSet.getString("customer_name")).thenReturn("myCustomerName");
// Launch the method against your mock
SomeClass someClass = new SomeClass();
CItem item = someClass.convert(resultSet);
// Check the result
Assert.assertNotNull(item);
Assert.assertEquals("myId", item.getHinumber());
Assert.assertEquals("myHost", item.getHostname());
Assert.assertEquals("myOS", item.getOs());
Assert.assertEquals("myCustomerName", item.getTenant());
}
}
如果您的 class 不处理数据库访问,接受 ResultSet 作为参数感觉就像代码味道。
您可以使用 Mockito 或 Power Mock 等模拟框架来创建模拟结果集。但是你不应该嘲笑你没有写的 classes(即图书馆/ JDK classes)。
假设您的 ResultSet 表示订单 table 中的一些订单数据。此方法真正需要的是 'order data',此时您不必担心如何以及从何处获取这些数据。所以你应该理想地定义一个这样的接口。
interface OrderRepository {
OrderData get();
}
然后你可以有一个 class 来实现这个处理 ResultSet 的接口 JDBCOrderRepository
。您的方法 ('convert') 现在将接受 OrderRepository 而不是 ResultSet。为了测试您的方法,您模拟 OrderRepository 而不是 ResultSet,后者更容易。
现在您将如何测试 JDBCOrderRepository
?好吧,也许您应该使用 运行 DB 实例对其进行测试,这实际上是一个集成测试。
如何对无法实例化的对象进行单元测试?因为目前我有一个将 ResultSet 转换为对象的方法,但我不确定这是否违反了任何编程原则。
public CItem convert(ResultSet rs) {
CItem ci = new CItem ();
try {
ci.setHinumber(rs.getString("id"));
ci.setHostname(rs.getString("sysname"));
ci.setOs(rs.getString("zos"));
ci.setTenant(rs.getString("customer_name"));
//ci.setInstallation(rs.getField("installation_name"));
} catch (SQLException e) {
e.printStackTrace();
}
return ci;
}
是否仅仅因为它无法进行单元测试,我就需要寻找其他方法来解决这个问题?或者我能以某种方式伪造一个 ResultSet 对象吗?
如有任何帮助,我们将不胜感激。
您可以简单地模拟您的 ResultSet
为每个字段提供一个值并检查结果是否包含您期望的内容。
例如 Mockito,你的测试应该是这样的:
@RunWith(MockitoJUnitRunner.class)
public class SomeClassTest {
@Mock
private ResultSet resultSet;
@Test
public void testConvert() throws SQLException {
// Define the behavior of the mock for each getString method's call
Mockito.when(resultSet.getString("id")).thenReturn("myId");
Mockito.when(resultSet.getString("sysname")).thenReturn("myHost");
Mockito.when(resultSet.getString("zos")).thenReturn("myOS");
Mockito.when(resultSet.getString("customer_name")).thenReturn("myCustomerName");
// Launch the method against your mock
SomeClass someClass = new SomeClass();
CItem item = someClass.convert(resultSet);
// Check the result
Assert.assertNotNull(item);
Assert.assertEquals("myId", item.getHinumber());
Assert.assertEquals("myHost", item.getHostname());
Assert.assertEquals("myOS", item.getOs());
Assert.assertEquals("myCustomerName", item.getTenant());
}
}
如果您的 class 不处理数据库访问,接受 ResultSet 作为参数感觉就像代码味道。
您可以使用 Mockito 或 Power Mock 等模拟框架来创建模拟结果集。但是你不应该嘲笑你没有写的 classes(即图书馆/ JDK classes)。
假设您的 ResultSet 表示订单 table 中的一些订单数据。此方法真正需要的是 'order data',此时您不必担心如何以及从何处获取这些数据。所以你应该理想地定义一个这样的接口。
interface OrderRepository {
OrderData get();
}
然后你可以有一个 class 来实现这个处理 ResultSet 的接口 JDBCOrderRepository
。您的方法 ('convert') 现在将接受 OrderRepository 而不是 ResultSet。为了测试您的方法,您模拟 OrderRepository 而不是 ResultSet,后者更容易。
现在您将如何测试 JDBCOrderRepository
?好吧,也许您应该使用 运行 DB 实例对其进行测试,这实际上是一个集成测试。