我不确定我的DAO或DBUnit Test是否需要一些重构。有人可以指导我面临的情况吗?
我有一个DAO,它通过获取Connection
对象从数据库中获取一些数据,然后关闭所有资源(ResultSet
,Statement
和Connection
)。
我正在使用DBUnit框架测试此DAO,在此DBUnit测试中,我正在执行两个数据库操作:
1)创建一个表,然后从XML数据集文件加载数据
2)测试DAO中存在的实际getDataById(int id)
方法
问题是我的第二个getDataById(id)
方法无法获取数据库连接对象,因为我的DAO在执行上述步骤1时已将其关闭。
实际释放所有资源的代码段如下所示。
DAO.java(代码段)
public void releaseResources(ResultSet rs, Statement stmt, Connection cn) {
System.out.println("rs = " + rs);
System.out.println("stmt = " + stmt);
System.out.println("cn = " + cn);
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (cn != null) {
cn.close();
}
} catch (SQLException ex) {
System.out.println("Exception while closing DB resources rs, stmt or cn......." + ex);
}
}
因此,为了使我的DBUnit测试正常工作,我不得不重载上述releaseResources()方法,以便它不会关闭可以在
getDataById(int id)
单元测试中使用的连接对象。如下所示。** DAO.java(带有重载方法的代码段)**
//OVERLOADED JUST TO GET DBUNIT TESTS WORKING !!! :(
public void releaseResources(Statement stmt) {
System.out.println("\nReleasing db resources now.... 1111");
System.out.println("stmt = " + stmt);
try {
if (stmt != null) {
stmt.close();
}
} catch (SQLException ex) {
System.out.println("Exception while closing DB resources stmt......." + ex);
}
}
我不确定这是否是正确的设计。我可以如何改善呢?
完整的代码如下所示,以供进一步参考。
StateDaoTest.java
public class StateDaoTest {
protected static Connection connection;
protected static HsqldbConnection dbunitConnection;
protected static StateDao dao = new StateDao();
@BeforeClass
public static void setupDatabase() throws Exception {
Class.forName("org.hsqldb.jdbcDriver");
connection = DriverManager.getConnection("jdbc:hsqldb:mem:my-project-test;shutdown=true");
dbunitConnection = new HsqldbConnection(connection, null);
}
@Before
public void createTable() throws SQLException {
dao.setConnection(connection);
dao.createTables();
}
protected IDataSet getDataSet(String name) throws Exception {
InputStream inputStream = getClass().getResourceAsStream(name);
assertNotNull("file" + name + " not found in classpath", inputStream);
Reader reader = new InputStreamReader(inputStream);
FlatXmlDataSet dataset = new FlatXmlDataSet(reader);
return dataset;
}
@AfterClass
public static void closeDatabase() throws Exception {
System.out.println("\ninto the closeDatabase() method...");
System.out.println("connection = " + connection);
System.out.println("dbunitConnection = " + dbunitConnection);
if (connection != null) {
connection.close();
connection = null;
}
if (dbunitConnection != null) {
dbunitConnection.close();
dbunitConnection = null;
}
}
@Test
public void testGetStateById() throws Exception {
IDataSet setupDataSet = getDataSet("/states.xml");
DatabaseOperation.CLEAN_INSERT.execute(dbunitConnection, setupDataSet);
State state = dao.getStateById(1);
assertNotNull(state);
assertEquals("Pennsylvania", state.getName());
assertEquals("PA", state.getStateCode());
assertNotNull(state.getTaxPct());
assertEquals("Y", state.getActive());
}
}
StateDao.java
public class StateDao {
private Connection connection;
public void setConnection(Connection connection) {
this.connection = connection;
}
//added for dbunit tests
public void createTables() throws SQLException {
String sql = "CREATE TABLE states (stateId INTEGER GENERATED BY DEFAULT AS IDENTITY(START WITH 1), "
+ "stateCd VARCHAR(10), name VARCHAR(20), taxPct NUMERIC, active CHAR(1))";
Statement stmt = null;
try {
stmt = connection.createStatement();
stmt.execute(sql);
} finally {
releaseResources(stmt);
}
}
public State getStateById(long id) {
String sql = "SELECT * FROM states WHERE stateId = " + id;
Statement stmt = null;
ResultSet rs = null;
State state = null;
System.out.println(sql);
try {
stmt = connection.createStatement();
rs = stmt.executeQuery(sql);
while (rs != null && rs.next()) {
String stateId = StringUtils.defaultString(rs.getString("stateId"));
String stateCd = StringUtils.defaultString(rs.getString("stateCd"));
String name = StringUtils.defaultString(rs.getString("name"));
String taxPct = StringUtils.defaultIfEmpty(rs.getString("taxPct"), "0");
String active = StringUtils.defaultString(rs.getString("active"));
state = new State(new Integer(stateId), stateCd, name, new BigDecimal(taxPct), active);
System.out.println("state = " + state);
}
System.out.println("state = " + state);
} catch (SQLException ex) {
System.out.println("Exception whiile fetching data for a state......." + ex);
} finally {
releaseResources(rs, stmt, connection);
}
return state;
}
public void releaseResources(ResultSet rs, Statement stmt, Connection cn) {
System.out.println("\nReleasing db resources now....2222");
System.out.println("rs = " + rs);
System.out.println("stmt = " + stmt);
System.out.println("cn = " + cn);
try {
if (rs != null) {
rs.close();
}
if (stmt != null) {
stmt.close();
}
if (cn != null) {
cn.close();
}
} catch (SQLException ex) {
System.out.println("Exception while closing DB resources rs, stmt or cn......." + ex);
}
}
//added for dbunit tests
public void releaseResources(Statement stmt) {
System.out.println("\nReleasing db resources now.... 1111");
System.out.println("stmt = " + stmt);
try {
if (stmt != null) {
stmt.close();
}
} catch (SQLException ex) {
System.out.println("Exception while closing DB resources stmt......." + ex);
}
}
}
最佳答案
我会继续使用重载的releaseResources
方法。如果连接是从外部传入的,则dao不拥有它,也不应该关闭它。而是应由创建连接的同一类分别关闭该连接。因此,应将getStateById
更改为仅关闭resultSet和语句,并在其他位置关闭该连接。
您可以添加releaseResources
的额外重载以采用resultSet和语句,或者如果您使用的是Java 7,则可以创建一个方法:releaseResouces(Closeable... closeables)
。我将使此方法成为单独类的公共静态方法,以便任何类都可以使用它。
关于java - DAO设计模式与DBUnit代码,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/29954583/