您的位置:软件测试 > 开源软件测试 > 开源单元测试工具 >
对DAO编写单元测试
作者:网络转载 发布时间:[ 2013/2/19 15:12:51 ] 推荐标签:

  下面,我们开始对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();

  }

  }

  );

  }

  }

上一页1234下一页
软件测试工具 | 联系我们 | 投诉建议 | 诚聘英才 | 申请使用列表 | 网站地图
沪ICP备07036474 2003-2017 版权所有 上海泽众软件科技有限公司 Shanghai ZeZhong Software Co.,Ltd