通常我們的bs模式應(yīng)同都是5層構(gòu)架體系的:DAO BL Action Taglib JSP
在這5層之中,只有jsp是非java代碼的,所以也是比較難以進(jìn)行單元測(cè)試的一層
而且jsp作為表現(xiàn)層來說呢,通常變化也比較大。所以對(duì)jsp編寫代碼測(cè)試的代價(jià)要遠(yuǎn)大于人工直接對(duì)頁面樣式進(jìn)行測(cè)試。
這篇文章主要將針對(duì)除去jsp以外的另外4層相關(guān)單元測(cè)試的基本框架進(jìn)行了一些討論:
首先我們要在單元測(cè)試前問自己一個(gè)問題:?jiǎn)卧獪y(cè)試的目的究竟是為了什么?
為了讓我們的項(xiàng)目更加時(shí)髦?為了讓我寫的代碼沒有bug?
我個(gè)人覺得單元測(cè)試的目的就是為了能夠用輕易的重復(fù)對(duì)代碼的測(cè)試!
下面我將對(duì)每一層的目的是什么,單元測(cè)試的目的是什么,還有改層單元測(cè)試的相關(guān)問題進(jìn)行講述
1、DAO層
DAO的目的:根據(jù)指定的參數(shù)對(duì)相關(guān)的數(shù)據(jù)對(duì)象進(jìn)行處理
基本操作有查詢操作 對(duì)數(shù)據(jù)源無影響 有返回值
增改操作 影響數(shù)據(jù)源 無返回值
刪除操作 影響數(shù)據(jù)源 無返回值
從上面我們可以看出,DAO的test主要是針對(duì)DAO的3種操作進(jìn)行測(cè)試
對(duì)于查詢操作我們可以從返回的結(jié)果集來進(jìn)行判斷
而對(duì)于增改操作和刪除操作我們就是只能在方法調(diào)用后對(duì)數(shù)據(jù)源進(jìn)行判斷了
這里,現(xiàn)在一般DAO層我們都會(huì)使用Spring+hibernate來進(jìn)行構(gòu)建,那么一個(gè)DAO的實(shí)例就需要引入到spring和DAO的相關(guān)配置了。而且由于牽扯到外部環(huán)境,所以這里外部環(huán)境的處理可以采用兩種方式,一種是直接使用數(shù)據(jù)庫(kù),這里就需要有一個(gè)真實(shí)的數(shù)據(jù)源存在了 二是模擬一個(gè)數(shù)據(jù)源,比如使用內(nèi)存數(shù)據(jù)庫(kù)或者文本數(shù)據(jù)庫(kù)來建立一個(gè)模擬環(huán)境,方便單機(jī)進(jìn)行測(cè)試
而且由于DAO是由Spring來進(jìn)行管理的,所以在測(cè)試的時(shí)候需要加載Spring的上下文來獲取dao的bean,關(guān)于spring的加載我使用的是spring-mock,它的好處是在事物處理后可以對(duì)相關(guān)的數(shù)據(jù)庫(kù)操作進(jìn)行rollback
2、BL層
BL層的目的:根據(jù)業(yè)務(wù)邏輯對(duì)業(yè)務(wù)處理進(jìn)行封裝
以往其實(shí)我們有時(shí)候習(xí)慣把一些業(yè)務(wù)邏輯代碼放置到上層DAO或者下層Action,taglib中
所以我總結(jié)了一下,基本的業(yè)務(wù)邏輯有:
參數(shù)的驗(yàn)證和判斷
業(yè)務(wù)邏輯錯(cuò)誤處理
業(yè)務(wù)規(guī)則判斷
所以針對(duì)于這些功能我們可以把原本屬于BL的代碼歸還給BL了,然后針對(duì)于bl的幾個(gè)功能就可以清晰地編寫單元測(cè)試了,這時(shí)候一般會(huì)用到做單元測(cè)試時(shí)比較有用的一個(gè)副產(chǎn)品:重構(gòu)。而這個(gè)副產(chǎn)品的價(jià)值將會(huì)在你重構(gòu)后體現(xiàn)出來,DAO,BL,ACTION,taglib的代碼職責(zé)更加明晰了,該做什么判斷的就座什么判斷
BL這層一般也是用Spring來進(jìn)行管理的,所以我們還是需要加載spring的上下文,當(dāng)然也可以不加載Spring,然后根據(jù)接口模擬一個(gè)DAO出來,但是我一般覺得這種模擬花消比較大,這個(gè)代價(jià)是否值得一直是我所懷疑的
3、Action層
action層的目的:對(duì)于請(qǐng)求進(jìn)行跳轉(zhuǎn)控制
一個(gè)控制層方法的主要功能有:獲取參數(shù),調(diào)用BL對(duì)參數(shù)進(jìn)行執(zhí)行,根據(jù)執(zhí)行的結(jié)果進(jìn)行頁面參數(shù)賦值,跳轉(zhuǎn)到結(jié)果頁面
當(dāng)然上面除了跳轉(zhuǎn)的到結(jié)果頁以外其他功能都不是必須的
針對(duì)于上述功能action的單元測(cè)試基本框架是:封裝請(qǐng)求參數(shù),發(fā)送請(qǐng)求,判斷所需的頁面bean和跳轉(zhuǎn)的結(jié)果頁面是否正確
這里牽扯到對(duì)于請(qǐng)求環(huán)境的模擬,一般不同的前臺(tái)構(gòu)架會(huì)有不同的模擬方法,struts下我使用的是strutstescase,它可以較為完整的讀取Struts配置文件
當(dāng)然一般在action中會(huì)用到Spring的上下文獲取bl,由于之前已經(jīng)對(duì)bl進(jìn)行了測(cè)試確認(rèn),所以我建議可以直接使用實(shí)際的bl,而不是再花費(fèi)代價(jià)開發(fā)一個(gè)模擬的BL
4、taglib層
taglib層目的:根據(jù)參數(shù)在頁面上按照固定的樣式輸出
一個(gè)標(biāo)簽的基本功能有:獲取參數(shù),調(diào)用BL對(duì)參數(shù)進(jìn)行執(zhí)行,把執(zhí)行結(jié)果放到指定樣式中,把得到的頁面代碼輸出
相對(duì)來說獲取參數(shù),調(diào)用BL對(duì)參數(shù)進(jìn)行執(zhí)行,把得到的頁面代碼輸出,比較固定,測(cè)試的意義不大,所以主要測(cè)試的就是把執(zhí)行結(jié)果放到指定樣式中這個(gè)功能。這個(gè)功能通常就是給一個(gè)結(jié)果集參數(shù)然后組合返回一個(gè)StringBuffer,所以測(cè)試起來也比較容易
但是taglib在使用的時(shí)候也需要的Spring甚至Struts的配置,這就需要在初始化的時(shí)候把相關(guān)環(huán)境也要加載進(jìn)來
這里大家因該可以看出我的單元測(cè)試并不是完全獨(dú)立的,而是伴隨漸進(jìn)的按照DAO,BL,Action,taglib這樣的順序引入環(huán)境,這樣一個(gè)可以減少測(cè)試開發(fā)的代價(jià),一個(gè)是可以增加測(cè)試的準(zhǔn)確性
在上面的描述中我們基本上了解了4層單元測(cè)試的基本目的和結(jié)構(gòu)
下一篇文章中我會(huì)針對(duì)各個(gè)層的具體測(cè)試方法是用代碼進(jìn)行講解 :)