对J2EE中的DAO组件编写单元测试

发表于:2008-5-15 13:58

字体: | 上一篇 | 下一篇 | 我要投稿

 作者:未知    来源:网络转载

        下面,我们开始对DAO组件编写单元测试。前面提到了HSQLDB这一小巧的纯Java数据库。HSQLDB除了提供完整的JDBC驱动以及事务支持外,HSQLDB还提供了进程外模式(与普通数据库类似)和进程内模式(In-Process),以及文件和内存两种存储模式。我们将HSQLDB设定为进程内模式及仅使用内存存储,这样,在运行JUnit测试时,可以直接在测试代码中启动HSQLDB。测试完毕后,由于测试数据并没有保存在文件上,因此,不必清理数据库。

  此外,为了执行批量测试,在每个独立的DAO单元测试运行前,我们都执行一个初始化脚本,重新建立所有的表。该初始化脚本是通过HibernateTool自动生成的,稍后我们还会讨论。下图是单元测试的执行顺序:

对DAO编写单元测试 图-2

        在编写测试类之前,我们首先准备了一个TransactionCallback抽象类,该类通过Template模式将DAO调用代码通过事务包装起来:

 public abstract class TransactionCallback {
  public final Object  execute() throws Exception {
  Transaction tx =  HibernateUtil.getCurrentSession().beginTransaction();
  try {
  Object r =  doInTransaction();
  tx.commit();
  return r;
  }
  catch(Exception e) {
  tx.rollback();
  throw e;
  }
  }
  // 模板方法:
  protected abstract Object  doInTransaction() throws Exception;
  }
        其原理是使用JDK提供的动态代理。由于JDK的动态代理只能对接口代理,因此,要求DAO组件必须实现接口。如果只有具体的实现类,则只能考虑CGLIB之类的第三方库,在此我们不作更多讨论。

        下面我们需要编写DatabaseFixture,负责启动HSQLDB数据库,并在@Before方法中初始化数据库表。该DatabaseFixture可以在所有的DAO组件的单元测试类中复用:

 public class DatabaseFixture {
  private static Server  server = null; // 持有HSQLDB的实例
  private static final  String DATABASE_NAME = "javaeedev"; // 数据库名称
  private static final  String SCHEMA_FILE = "schema.sql"; // 数据库初始化脚本
  private static final  List<String> initSqls = new ArrayList<String>();
 @BeforeClass // 启动HSQLDB数据库
  public static void  startDatabase() throws Exception {
  if(server!=null)
  return;
  server = new  Server();
  server.setDatabaseName(0,  DATABASE_NAME);
  server.setDatabasePath(0, "mem:" + DATABASE_NAME);
  server.setSilent(true);
  server.start();
  try {
  Class.forName("org.hsqldb.jdbcDriver");
  }
  catch(ClassNotFoundException cnfe) {
  throw new  RuntimeException(cnfe);
  }
  LineNumberReader  reader = null;
  try {
  reader = new  LineNumberReader(new     InputStreamReader(DatabaseFixture.class.getClassLoader().getResourceAsStream(SCHEMA_FILE)));
  for(;;) {
  String line =  reader.readLine();
  if(line==null) break;
  // 将text类型的字段改为varchar(2000),因为HSQLDB不支持text:
  line =  line.trim().replace(" text ", " varchar(2000)  ").replace("  text,", " varchar(2000),");
  if(!line.equals(""))
  initSqls.add(line);
  }
  }
  catch(IOException e)  {
  throw new  RuntimeException(e);
  }
  finally {
  if(reader!=null)  {
  try {  reader.close(); } catch(IOException e) {}
  }
  }
  }
 @Before // 执行初始化脚本
  public void initTables()  {
  for(String sql :  initSqls) {
  executeSQL(sql);
  }
  }
static Connection  getConnection() throws SQLException {
  return  DriverManager.getConnection("jdbc:hsqldb:mem:" + DATABASE_NAME,  "sa", "");
  }
static void  close(Statement stmt) {
  if(stmt!=null) {
  try {
  stmt.close();
  }
  catch(SQLException e) {}
  }
  }
static void  close(Connection conn) {
  if(conn!=null) {
  try {
  conn.close();
  }
  catch(SQLException e) {}
  }
  }
static void  executeSQL(String sql) {
  Connection conn =  null;
  Statement stmt =  null;
  try {
  conn =  getConnection();
  boolean  autoCommit = conn.getAutoCommit();
  conn.setAutoCommit(true);
  stmt = conn.createStatement();
  stmt.execute(sql);
  conn.setAutoCommit(autoCommit);
  }
  catch(SQLException e)  {
  log.warn("Execute failed: " + sql + "\nException: "  + e.getMessage());
  }
  finally {
  close(stmt);
  close(conn);
  }
  }
public static Object  createProxy(final Object target) {
  return  Proxy.newProxyInstance(
  target.getClass().getClassLoader(),
  target.getClass().getInterfaces(),
  new  InvocationHandler() {
  public  Object invoke(Object proxy, final Method method, final Object[] args) throws  Throwable {
  return new TransactionCallback() {
  @Override
  protected Object doInTransaction() throws Exception {
  return method.invoke(target, args);
  }
  }.execute();
  }
  }
  );
  }
  }

54/5<12345>
《2023软件测试行业现状调查报告》独家发布~

关注51Testing

联系我们

快捷面板 站点地图 联系我们 广告服务 关于我们 站长统计 发展历程

法律顾问:上海兰迪律师事务所 项棋律师
版权所有 上海博为峰软件技术股份有限公司 Copyright©51testing.com 2003-2024
投诉及意见反馈:webmaster@51testing.com; 业务联系:service@51testing.com 021-64471599-8017

沪ICP备05003035号

沪公网安备 31010102002173号