閱讀提要 StrutsTestCase是一個強有力的易於使用的針對Struts行為的測試框架
StrutsTestCase
並與傳統型JUnit測試相結合
將會帶給你一個相當高的測試覆蓋率並提高你的產品的可靠性
一引言 StrutsTestCase是一個用於測試Struts行為的基於Junit的測試框架
如果你使用Struts
那麼你會注意到它可以提供給你一種容易而有效的方式來測試你的應用程序的Struts行為類
典型的J
EE應用程序都是分層構建的
如圖
所示
·DAO層封裝了數據庫存取
Hibernate映射和對象類
Hibernate查詢
實體EJBs
或一些其它的實體
關系持續性技術都可以在這一層找到
·商業層包含更高級的商業服務
理想地
這個商業層將是相對獨立於數據庫實現
在這個層上經常使用會話EJBs
·描述層包含為用戶顯示應用程序數據並解釋用戶請求
在一個Struts應用程序中
這一層典型地使用JSP/JSTL頁面來顯示數據並且使用Struts行為來解釋用戶查詢
·客戶層基本上是運行於用戶機器上的web浏覽器
客戶端邏輯(例如
JavaScript)有時被放在這裡
盡管很難對其進行有效地測試
圖
典型的J
EE架構
DAO和商業層的測試或者可以通過使用經典的JUnit測試或者使用各種JUnit擴展來進行
具體依賴於架構的實現細節
DbUnit是一種用來進行數據庫單元測試的良好選擇
另一方面
測試Struts行為總是很困難的事情
即使在商業層嚴格地限制於商業層的構建時
Struts行為也總要包含重要數據校驗
轉換和流程控制代碼
不對Struts行為進行測試將會在代碼覆蓋率上留下一道很髒的鴻溝
StrutsTestCase會讓你填充這條鴻溝
對行為層進行單元測試還帶來其它一些益處
·可以更好地規劃視圖和控制層
從而使之更為簡單清晰
·更容易重構行為類
·避免冗余的未使用的行為類
·測試實例有助於對行為層進行歸檔
這在創建屏幕時是很有用的
上面是基於測試開發的典型好處
並且它們可以應用於在各種情況下使用的Struts行為層
二StrutsTestCase簡介 StrutsTestCase工程提供了一種靈活又方便的方法來從JUnit框架內測試Struts行為
它能夠使你對你的Struts行為進行白色盒子測試
通過在調用行為後建立請求參數並檢查結果Request或Session的狀態
StrutsTestCase允許或者是一個模仿測試方式
這時框架模擬web服務器容器
或者是一個容器內方式
這時使用Cactus框架來從服務器容器(例如Tomcat)內部運行測試
一般地
我比較喜歡模仿測試方式
因為它更為輕量級的且運行更快些
並因此允許較寬松的開發周期
所有的StrutsTestCase單元測試類或者派生於MockStrutsTestCase以進行模仿測試
或者派生於CactusStrutsTestCase以進行容器內測試
在此我們先討論模仿測試
因為它要求較少的配置並且運行較快些
三實戰StrutsTestCase 為了使用StrutsTestCase來測試這個行為
我們創建一個擴展類MockStrutsTestCase的新類
這個類提供一系列方法來構建一個模擬的HTTP請求
調用相應的Struts行為以及一旦在行為完成時校驗應用程序狀態
可以設想有一個在線的具有多條件查找功能的住所數據庫
這個查找函數是通過/search
do行為實現的
這個行為將基於指定的條件完成一次多條件查找
並把結果列表放置在一個稱為results的請求范圍屬性中
例如
下列URL應該顯示一個在法國的所有的住所結果列表
/search
do?country=FR
現在
假定我們想要使用一個測試驅動的方式來實現這個方法
我們創建該行為類並更新Struts配置文件
我們還編制測試實例來測試(空的)這個行為類
通過使用一種嚴格的測試驅動的開發方法
我們可以首先創建測試實例
然後實現代碼來匹配該測試實例
在實踐中
具體的順序可能因要測試的代碼而有所不同
起始的測試情形看去如下樣子
public void testSearchByCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
actionPerform();
}
在此
我們建立要調用的路徑(setRequestPathInfo())並且添加一請求參數(addRequestParameter())
然後
我們用actionPerform()來調用行為類
這將驗證Struts配置並且調用相應的行動類
但是將不測試該行為的實際所做
為此
我們需要驗證行動的結果
public void testSearchByCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
actionPerform();
verifyNoActionErrors();
verifyForward(
success
);
assertNotNull(request
getAttribute(
results
));
}
在此
我們檢查三件事情
·不存在ActionError消息(verifyNoActionErrors())
·返回
success
forward
·results屬性被放置到請求范圍中
如果我們正在使用tiles
我們也可以通過使用verifyTilesForward()來保證
success
forward實際上指定正確的tiles定義
public void testSearchByCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
actionPerform();
verifyNoActionErrors();
verifyTilesForward(
success
accommodation
list
def
);
assertNotNull(request
getAttribute(
results
));
}
在實踐中
我們可能想在該測試結果上實現特定的商業測試
例如
假定結果屬性是一個List
它包含一列約
個Hotel域對象
並且我們想要保證所有在該列表中的賓館都在法國
為了實現這種類型的測試
代碼將非常相似於標准JUnit測試
public void testSearchByCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
actionPerform();
verifyNoActionErrors();
verifyForward(
success
);
assertNotNull(request
getAttribute(
results
));
List results = (List) request
getAttribute(
results
);
assertEquals(results
size()
);
for (Iterator iter = erator();
iter
hasNext();) {
Hotel hotel = (Hotel) iter
next();
assertEquals(hotel
getCountry
TestConstants
FRANCE);
}
}
當你測試更復雜的情形時
你可能想要測試系列化的行為
例如
假定用戶在法國查詢所有的賓館並且點擊一個入口來顯示相應的查詢細節
假定我們有一個Struts行為來顯示一個給定賓館的細節信息
可以作如下調用
/displayDetails
do?id=
通過使用StrutsTestCase
我們能夠容易地在相同的測試情形下模仿一系列的行為
一個用戶在法國查詢所有的賓館
然後點擊一個入口來顯示相應的查詢細節
public void testSearchAndDisplay() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
actionPerform();
verifyNoActionErrors();
verifyForward(
success
);
assertNotNull(request
getAttribute(
results
));
List results = (List) request
getAttribute(
results
);
assertEquals(results
size()
);
Hotel hotel = (Hotel) results
get(
);
setRequestPathInfo(
/displayDetails
do
);
addRequestParameter(
id
hotel
getId());
actionPerform();
verifyNoActionErrors();
verifyForward(
success
);
Hotel hotel = (Hotel)request
getAttribute(
hotel
);
assertNotNull(hotel);
}
四測試Struts錯誤處理 測試錯誤處理也是一件很重要的事情
假定
如果指定一個無效的國家代碼時
我們想要檢查應用程序仍然運行良好
為此
我們可以寫一個新的測試方法並且使用verifyActionErrors()檢查返回的Struts ErrorMessages:
public void testSearchByInvalidCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
XX
);
actionPerform();
verifyActionErrors( new String[] {
error
unknown
country
});
verifyForward(
failure
);
}
有時你想直接在ActionForm對象中進行數據校驗
為此
你可以使用getActionForm()
如下所示:
public void testSearchByInvalidCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
XX
);
actionPerform();
verifyActionErrors( new String[] {
error
unknown
country
});
verifyForward(
failure
);
SearchForm form = (SearchForm) getActionForm();
assertEquals(
Scott
form
getCountry(
XX
));
}
在此
我們可以確保在出現錯誤後無效的國家代碼被正確地存儲在ActionForm中
五定制測試環境 重載setUp()方法有時是很有用的
它讓你指定非缺省的配置選項
在這個例子中
我們使用一個不同的struts
config
xml文件並且不激活XML配置文件校驗:
public void setUp() {
super
setUp();
setConfigFile(
/WEB
INF/my
struts
config
xml
);
setInitParameter(
validating
false
);
}
六第一級性能測試 測試一個行為或一系列的行為是一個十種優秀的測試方式
它要求能夠存取響應次數
從Struts行為中進行測試允許你校驗全局的服務器端性能(當然
除去產生JSP頁面)
為了盡快隔離和移除性能問題以及把它們集成到構建過程中以幫助避免性能回退
在單元
測試級上進行一些第一級性能測試是個很不錯的注意
下面是我用來進行第一級Struts性能測試的基本原則:
·用盡可能多的組合來測試多條件搜索查詢(為了檢查這些索引已被正確定義了)
·測試大容量的查詢(返回大量結果的查詢)來檢查響應次數和結果頁面(如果使用的話)
·測試單個的和重復的查詢(來檢查緩沖性能
如果使用緩沖策略的話)
有一些開源庫可以用於幫助進行性能測試
例如由Mike Clark維護的JUnitPerf
然而
把它們集成到StrutsTestCase中可能有些復雜
在很多情況下
一個簡單的定時器即可以實現這一功能
下面是一種簡單而有效的實現第一級性能測試的方法
public void testSearchByCountry() {
setRequestPathInfo(
/search
do
);
addRequestParameter(
country
FR
);
long t
= System
currentTimeMillis();
actionPerform();
long t
= System
currentTimeMillis()
t
;
log
debug(
Country search request processed in
+ t
+
ms
);
assertTrue(
Country search too slow
t
>=
)
}
七結論 一般地
單元測試是進行靈敏編程特別是基於測試開發的一個基本部分
StrutsTestCase為我們提供一種容易並且有效的方法來單元測試Struts行為
否則
如果使用JUnit來進行單元測試則相當困難
From:http://tw.wingwit.com/Article/program/Java/ky/201311/27868.html