。
1. DAO測試
UserDAOTest用于測試UserDAO這個(gè)接口和它的實(shí)現(xiàn)UserDAOHibernate,它在test/dao/**/dao/中。
所有的DAOTest都繼承自BaseDAOTestCase,BaseDAOTestCase繼承自TestCase。這個(gè)父類已經(jīng)為我們寫好了從Spring加載ApplicationContext的方法。
setUp()里做了在測試之前的初始化工作,創(chuàng)建了UserDAO和RoleDAO的實(shí)例,tearDown()里做銷毀工作,這是每個(gè)Junit測試類都要做的事。
以testUpdateUser()方法為例,該方法主要用于測試UserDAO的saveUser()方法是否正確。首先調(diào)用getUser()獲得用戶“tomcat”的信息,并修改其地址,然后調(diào)用saveUser()方法保存修改的記錄。重新獲得“tomcat”的信息,校驗(yàn)其地址是否為新地址,如果地址為新地址,測試成功。接下來把“tomcat”的version屬性的值置空(version為驗(yàn)證當(dāng)前記錄是否為新記錄的標(biāo)志,null表示新紀(jì)錄),重新保存“tomcat”,此時(shí)hibernate會(huì)認(rèn)為該記錄為新記錄,進(jìn)行insert操作,但username字段為主鍵不能重復(fù),因此應(yīng)該拋出異常。如果捕獲到異常,測試成功。
在控制臺(tái)進(jìn)入項(xiàng)目根目錄,鍵入ant test-dao -Dtestcase=UserDAO,如果出現(xiàn)BUILD SUCCESSFUL,說明測試成功。這樣,我們不需要寫Manager、Action、JSP,不需要運(yùn)行容器也可以確保我們的類正確了。
2. Manager測試
接下來繼續(xù)看測試UserManager的類UserManagerTest。它在test/service/**/service/中,繼承自BaseManagerTestCase,這個(gè)父類起著與BaseDAOTestCase類似的作用。
與UserDAOTest不同的是UserManagerTest使用了jMock幫助其測試。jMock用于解決UserManager的依賴,因?yàn)閁serManager中需要調(diào)用UserDAO的方法,而單元測試的基本規(guī)則是一次只測試一個(gè)對(duì)象,jMock幫助你把UserManager孤立起來,使它不會(huì)受到UserDAO的影響,我們來看它到底怎么做。
在setUp()里,我們把UserDAO和RoleDAO放到Mock中,讓Mock來做UserDAO和RoleDAO的代理,并將這兩個(gè)“假冒的”DAO注入到UserManager中。
還是以testSaveUser()為例來看這個(gè)test類怎么工作。首先創(chuàng)建User對(duì)象,設(shè)置用戶名為“tomcat”,權(quán)限為“user”。然后我們告訴Mock當(dāng)UserManager調(diào)用UserDAO的getUser()方法并參數(shù)是“tomcat”時(shí),我們期待UserDAO返回我們剛剛創(chuàng)建的那個(gè)對(duì)象。接下來調(diào)用UserManager的getUser()方法以獲得“tomcat”的信息。修改電話號(hào)碼的內(nèi)容。然后重置我們對(duì)Mock的要求。這次我們要求當(dāng)UserManager調(diào)用UserDAO的saveUser方法時(shí),不返回任何值。然后調(diào)用UserManager的saveUser()方法,校驗(yàn)user是否為新的電話號(hào)碼和權(quán)限是否還是一個(gè),若是,測試成功。verify()用于檢查所有應(yīng)該調(diào)用的方法是否都被調(diào)用了。通常來說,每對(duì)Mock對(duì)象調(diào)用了一次expects(),使用完后都要執(zhí)行一次verify()。
在控制臺(tái)執(zhí)行ant test-service -Dtestcase=UserManager,看看結(jié)果。
3. Action測試
我們繼續(xù)看test/web/**/action下的UserActionTest。它繼承自BaseStrutsTestCase,BaseStrutsTestCase繼承MockStrutsTestCase,這個(gè)父類也做了類似BaseManagerTestCase的工作。
Action是一個(gè)控制器,主要用于接收視圖層的請(qǐng)求,調(diào)用模型層的方法,然后返回視圖層。在這里我們不關(guān)心模型層或視圖層,我們只要關(guān)心Action是否能夠正確的得到請(qǐng)求和響應(yīng)請(qǐng)求,以及能夠正確的根據(jù)請(qǐng)求轉(zhuǎn)向。MockStrutsTestCase給了我們測試這方面很好的支持。
以testSave()為例,首先創(chuàng)建一個(gè)UserForm,在里面放入部分?jǐn)?shù)據(jù),將UserForm放入該Action所對(duì)應(yīng)的范圍內(nèi)。使用setRequestPathInfo()設(shè)置請(qǐng)求路徑為“/saveUser”,使用addRequestParameter()添加好請(qǐng)求參數(shù),actionPerform()方法將模擬請(qǐng)求的全過程。然后使用verifyForward()方法驗(yàn)證請(qǐng)求轉(zhuǎn)發(fā)路徑是否正確。并驗(yàn)證能不能在Action范圍內(nèi)得到UserForm。
運(yùn)行ant test-web -Dtestcase=UserAction,OK。
要注意一點(diǎn),這里的單元測試雖然繼承自MockStrutsTestCase,但沒有使用Mock,也就是說,它會(huì)真正執(zhí)行到所有相關(guān)的方法,包括修改數(shù)據(jù)庫。
4. JSP測試
我們同樣可以對(duì)JSP進(jìn)行測試。這里有一個(gè)工具叫做Canoo WebTest,它使用xml配置的方式來測試JSP。
進(jìn)入test/web/,有一個(gè)web-tests.xml文件,里面有所有struts-config.xml中存在的path的測試。
以SaveUser這個(gè)target為例,我們做一個(gè)簡單的說明。測試步驟包含在steps中,invoke中給這個(gè)step定一個(gè)ID號(hào),設(shè)置請(qǐng)求的url:editProfile.html。接下來驗(yàn)證JSP頁面的title是否與預(yù)期的一致。其中{webapp.prefix}和{userProfile.title}的內(nèi)容在WEB-INF\classes中的ApplicationResources中定義。接下來給表單中的文本域填寫內(nèi)容,使用clickbutton點(diǎn)擊保存按鈕,驗(yàn)證保存后的頁面標(biāo)題是否為預(yù)期的標(biāo)題。
這一測試需要運(yùn)行容器,因此首先運(yùn)行Tomcat,再在控制臺(tái)鍵入ant test-canoo -Dtestcase=UserTests或ant test-jsp -Dtestcase=PersonTests。使用ant run-all-tests無需運(yùn)行Tomcat,Ant為你做這件事。