您的位置:軟件測(cè)試 > 開源軟件測(cè)試 > 開源單元測(cè)試工具 >
對(duì)DAO編寫單元測(cè)試
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時(shí)間:[ 2013/2/19 15:12:51 ] 推薦標(biāo)簽:

  下面,我們開始對(duì)DAO組件編寫單元測(cè)試。前面提到了HSQLDB這一小巧的純Java數(shù)據(jù)庫。HSQLDB除了提供完整的JDBC驅(qū)動(dòng)以及事務(wù)支持外,HSQLDB還提供了進(jìn)程外模式(與普通數(shù)據(jù)庫類似)和進(jìn)程內(nèi)模式(In-Process),以及文件和內(nèi)存兩種存儲(chǔ)模式。我們將HSQLDB設(shè)定為進(jìn)程內(nèi)模式及僅使用內(nèi)存存儲(chǔ),這樣,在運(yùn)行JUnit測(cè)試時(shí),可以直接在測(cè)試代碼中啟動(dòng)HSQLDB。測(cè)試完畢后,由于測(cè)試數(shù)據(jù)并沒有保存在文件上,因此,不必清理數(shù)據(jù)庫。

  此外,為了執(zhí)行批量測(cè)試,在每個(gè)獨(dú)立的DAO單元測(cè)試運(yùn)行前,我們都執(zhí)行一個(gè)初始化腳本,重新建立所有的表。該初始化腳本是通過HibernateTool自動(dòng)生成的,稍后我們還會(huì)討論。下圖是單元測(cè)試的執(zhí)行順序:
對(duì)DAO編寫單元測(cè)試 圖-2

  在編寫測(cè)試類之前,我們首先準(zhǔn)備了一個(gè)TransactionCallback抽象類,該類通過Template模式將DAO調(diào)用代碼通過事務(wù)包裝起來:

 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提供的動(dòng)態(tài)代理。由于JDK的動(dòng)態(tài)代理只能對(duì)接口代理,因此,要求DAO組件必須實(shí)現(xiàn)接口。如果只有具體的實(shí)現(xiàn)類,則只能考慮CGLIB之類的第三方庫,在此我們不作更多討論。

  下面我們需要編寫DatabaseFixture,負(fù)責(zé)啟動(dòng)HSQLDB數(shù)據(jù)庫,并在@Before方法中初始化數(shù)據(jù)庫表。該DatabaseFixture可以在所有的DAO組件的單元測(cè)試類中復(fù)用:

 public class DatabaseFixture {

  private static Server  server = null; // 持有HSQLDB的實(shí)例

  private static final  String DATABASE_NAME = "javaeedev"; // 數(shù)據(jù)庫名稱

  private static final  String SCHEMA_FILE = "schema.sql"; // 數(shù)據(jù)庫初始化腳本

  private static final  List<String> initSqls = new ArrayList<String>();
 @BeforeClass // 啟動(dòng)HSQLDB數(shù)據(jù)庫

  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),因?yàn)镠SQLDB不支持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 // 執(zhí)行初始化腳本

  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下一頁
軟件測(cè)試工具 | 聯(lián)系我們 | 投訴建議 | 誠(chéng)聘英才 | 申請(qǐng)使用列表 | 網(wǎng)站地圖
滬ICP備07036474 2003-2017 版權(quán)所有 上海澤眾軟件科技有限公司 Shanghai ZeZhong Software Co.,Ltd