您的位置:軟件測試 > 開源軟件測試 > 開源單元測試工具 >
測試Struts遺留的應(yīng)用程序
作者:網(wǎng)絡(luò)轉(zhuǎn)載 發(fā)布時間:[ 2013/2/1 16:06:18 ] 推薦標簽:

雖然 Struts 正在慢慢退出 Web 框架的歷史舞臺,但它的遺產(chǎn)仍然存在,存在的形式主要是需要測試和維護的應(yīng)用程序。這個月,Andrew Glover 向您介紹如何使用 JUnit 的 StrutsTestCase、DbUnit 以及在這個系列中迄今為止學到的一些工具,把以質(zhì)量為中心的方法用于 Struts 上的測試(可以這么說)。

基于 Java™ 的 Web 開發(fā)領(lǐng)域近出現(xiàn)了豐富的競爭性技術(shù)。啟動新項目的開發(fā)人員可以在許多不同的框架之間進行選擇,包括 JavaServer Faces、Tapestry、Shale、Grails 和 Seam (只列舉眾多機靈的名稱中的幾個)。很快,我們可以通過 JRuby 框架在 Java 編程中使用 Ruby on Rails 了!

但在不遠的過去,只有一個 Java Web 開發(fā)框架卓然而立。Struts 是第一個在 Java 世界掀起風暴的框架,而且多年以來,好像是如果一個項目不用 Struts 構(gòu)建沒有前途一樣。沒有 Struts 經(jīng)驗的 Java 開發(fā)人員很稀少,也很不幸,像的開發(fā)人員沒有聽說過 Ruby on Rails 一樣。
 
提高代碼質(zhì)量
不要錯過 Andrew 的附帶 討論組 ,可以得到迫切問題的答案。

即使 Struts 正慢慢地從舞臺中央退去(原來的基本框架,現(xiàn)在叫做 Struts 1,似乎正在退出 Web 框架的歷史舞臺),但它的遺產(chǎn)仍然存在,既以 Shale (請參閱 參考資料)的形式存在,又以運行在世界各地的成千上萬的遺留應(yīng)用程序的形式存在。因為許多企業(yè)寧愿測試和維護這些應(yīng)用程序而不愿意花錢重新編寫它們,所以理解 Struts 應(yīng)用程序的一些缺陷,以及如何圍繞它們進行重構(gòu),是個好主意。

這個月,我要把以質(zhì)量為核心的方法用于 Struts 應(yīng)用程序的測試場景。結(jié)合現(xiàn)實,這個場景圍繞著普遍的 Struts 構(gòu)造:深受喜愛的 Action 類。

1、2、3,行動!

Struts 的革新之一是把 Web 開發(fā)從 Servlet 移進了 Action 類。這些類包含業(yè)務(wù)邏輯,以 JavaBean 的形式(通常叫做 ActionForm)把數(shù)據(jù)傳送到 JSP。然后 JSP 處理應(yīng)用程序視圖。Struts 到 MVC 的方法非常容易掌握,以至于許多開發(fā)團隊冒失地闖進去,而很少考慮與 Action 相關(guān)的長期設(shè)計和維護問題。

 
測試和復(fù)雜性

我已經(jīng)發(fā)現(xiàn),在開發(fā)人員的測試和代碼的復(fù)雜性之間存在強烈的相關(guān)性:沒有其中一個的地方,通常也沒有另一個。高度復(fù)雜的編碼難于測試,結(jié)果是很少有人會真正為它編寫測試。反過來,編寫測試可以降低代碼的復(fù)雜性。因為給復(fù)雜代碼編寫測試更困難,而且因為會邊走邊測試,所以會發(fā)現(xiàn)自己朝著更簡單的代碼構(gòu)造前進。如果代碼太復(fù)雜,而且知道不得不測試它,您可能會在測試之前對復(fù)雜性進行重構(gòu)。不論如何看待,為不那么簡單的代碼編寫測試是消滅代碼復(fù)雜性的好實踐。

雖然在那個時候(過去的自由時光。┛赡軟]人想過,但 Struts Action 類通常成為復(fù)雜性的保護所。像在老的 EJB 架構(gòu)中聲名狼籍的會話 Facade 一樣,Action 類會成為特定業(yè)務(wù)過程的嚴格偽裝,或者通過直接調(diào)用 EJB,通過打開數(shù)據(jù)庫連接,或者通過調(diào)用其他高度依賴的對象。Action 類還有輸出耦合(通過 java.servlet API 包中的對象,例如 HttpServletRequest 和 HttpServletResponse),從而極難把它們隔離出來測試。

隔離出來測試 Action 類的困難意味著它們可以很容易變得相當復(fù)雜 —— 特別是當它們變成越來越深入地與遺留框架耦合的時候,F(xiàn)在我們來看這個困難在真實的遺留應(yīng)用程序場景中作用的情況。

測試挑戰(zhàn)

即使簡單的 Struts Action 類也會是個測試挑戰(zhàn)。例如,以清單 1 中的 execute() 方法為例;它看起來足夠簡單,可以測試,但是真的么?

清單 1. 這個方法看起來容易測試……

public ActionForward execute(ActionMapping mapping, ActionForm aForm,   HttpServletRequest req, HttpServletResponse res) throws Exception { try{     String newPassword = ((ChangePasswordForm)aForm).getNewPassword1();   String username = ((ChangePasswordForm)aForm).getUsername();   IUser user = DataAclearcase/" target="_blank" >ccessUtils.getDaos().getUserDao().findUserByUsername(username);   user.digestAndSetPassword(newPassword);   DataAccessUtils.getDaos().getUserDao().saveUser(user);  }catch(Throwable thr){         return findFailure(mapping, aForm, req, res); } return findSuccess(mapping, aForm, req, res); } 

圖 1. Action 類的輸出耦合

但是,像在圖 1 中可以看到的,在試圖隔離 ChangePasswordAction 類并檢驗 execute() 方法時,該類給出了一些有代表性的挑戰(zhàn)。為了有效地測試 execute() 方法,必須處理三層耦合。首先,到 Struts 自身的耦合;其次,Servlet API 代表一個障礙;后,到業(yè)務(wù)對象包的耦合,進一步檢查業(yè)務(wù)對象包,還會有數(shù)據(jù)訪問層使用 Hibernate 和 Spring。
 
每種情況一個 mock?

即使在我編寫本文時,我還可以聽到開發(fā)人員的嘲笑者 認為我的測試問題通過明智地使用 mock 對象能輕易解決。可以 用 mock 對象創(chuàng)建一級隔離,它會形成更容易的測試;但是,我要說的是,把目標對象通過 mock 排除所需要的付出級別,比起承認隔離測試困難所需要的付出,要多得多。在這種情況下,我會采用在更高層次上的測試,這級測試有時叫做集成測試。

對于更高的復(fù)雜性,請注意 清單 1 中的代碼如何把 aForm 參數(shù)轉(zhuǎn)換成 ChangePasswordForm 對象,它是 Struts ActionForm 類型。這些 JavaBeans 有一個 validate 方法,這個方法由 Struts 在調(diào)用 Action 類的 execute() 方法之前調(diào)用。

犯錯誤太容易了

在清單 2 中,可以看到所有這個復(fù)雜性會在哪里發(fā)生。ChangePasswordForm 的 validate() 方法的代碼片段演示了保證兩個屬性(newPassword1 和 newPassword2)不為空并彼此相等的簡單邏輯。但是,如果 Struts 發(fā)現(xiàn) errors 集合(類型為 ActionErrors)包含一些 ActionError 對象,會沿著錯誤路徑走,例如帶著出錯消息重新顯示 Web 頁面。

清單 2. ChangePasswordForm 的驗證邏輯

if((newPassword1 == null) || (newPassword1.length() < 1)) {  errors.add("newPassword1",     new ActionError("error.changePassword.newPassword1Required"));}if((newPassword2 == null) || (newPassword2.length() < 1)) {  errors.add("newPassword2",     new ActionError("error.changePassword.newPassword2Required"));}if((newPassword1 != null) && (newPassword2 != null)) {  if(!newPassword1.equals(newPassword2)) {    errors.add(ActionErrors.GLOBAL_ERROR,   new ActionError("error.changePassword.passwordsDontMatch"));  }} 


清單 1 和 清單 2 的代碼不特殊也不特定于某個領(lǐng)域。它是無數(shù)應(yīng)用程序中都包含的簡單口令修改邏輯。如果正在測試 Struts 遺留應(yīng)用程序,將不得不花些時間處理口令邏輯,但是如何用可重復(fù)的方式測試它呢?

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