引自我的博客:android 源碼下載部分單元測試代碼分析
最近因為業(yè)務(wù)需要嚷狞,在研究android源碼的下載部分。因為要考慮代碼質(zhì)量的問題,所以就針對源碼的測試用例做了一些分析啃洋,并在源碼用例的基礎(chǔ)上添加了我們自己增加接口部分的用例宏娄。測試代碼的分析比較偏門僻澎,網(wǎng)上也很少見逗堵,這里權(quán)作探討亚斋,歡迎糾錯。
在分析這個代碼之前帅刊,能想到的一些問題:
1.下載這部分涉及到網(wǎng)絡(luò)環(huán)境纸泡、數(shù)據(jù)庫、contentprovider赖瞒、廣播等依賴硬件或外部環(huán)境較多的部分女揭,如何測試;
2.網(wǎng)絡(luò)環(huán)境復(fù)雜多變栏饮,如何能夠測試全面吧兔;
3.我們了解下載系統(tǒng)的復(fù)雜程度,是以DownloadService為核心控制下載任務(wù)的刷新袍嬉,
DownloadProvider供增刪改查各種任務(wù)為基礎(chǔ)境蔼,供app用戶管理下載任務(wù)、查詢下載進(jìn)度和狀態(tài)伺通,真正下載的實現(xiàn)則在DownloadThread中——這樣一個復(fù)雜的模塊的測試從何下手箍土。
然后,大體分析一下測試源碼的結(jié)構(gòu)罐监,我使用EA導(dǎo)入代碼工程的方式生成了類圖涮帘,再大體調(diào)整了一下位置布局,很方便笑诅。
來仔細(xì)分析一下測試源碼的類結(jié)構(gòu):
1. 以繼承關(guān)系為骨架看的話调缨,可以分為三層疮鲫,很明顯抽象類是不能直接作為干活的測試類的,繼承關(guān)系中的葉子節(jié)點類才是真正跑用例的類弦叶。那么其余部分肯定是為跑測試做各方面的準(zhǔn)備俊犯;
2. 最基礎(chǔ)的 AbstractDownloadProviderFunctionalTest,是第一層的中心伤哺。左邊兩個是它的內(nèi)部類燕侠,并且還維護(hù)著這兩個內(nèi)部類的實體;右面是對下載系統(tǒng)源碼中SystemFacade的一個模擬實現(xiàn)類的依賴立莉,同樣維護(hù)著一個實體绢彤;在看各位組件的類名:TestContext、MockContentResolverWithNotify蜓耻、FakeSystemFacade茫舶,可以說是假貨一條街∩蔡剩總結(jié)來說饶氏,第一層就是以AbstractDownloadProviderFunctionalTest為中心的組合關(guān)系,該類維護(hù)了一系列假貨的實體有勾,那么大概齊是什么功能也能猜個八九了疹启,具體是怎樣還要讀源碼來驗證;
3. 第二層在繼承前類的同時又有拓展蔼卡。該層已經(jīng)有一個葉子類了喊崖,DownloadProviderFunctionalTest,從一些共有方法能看到測試用例的定義雇逞,同時根據(jù)類名也能看出一二贷祈;AbstractPublicApiTest則是它的兄弟類,繼續(xù)抽象喝峦,仔細(xì)一點可以看出這里添加了一個重要的實體:DownloadManager势誊,繼續(xù)做準(zhǔn)備吧,至于它的內(nèi)部類Download結(jié)構(gòu)上看不出什么谣蠢,還需要看接口和源碼才能了解具體功能粟耻;
4. 第三層,就都是葉子類了眉踱,也是大規(guī)模測試用例的聚集地挤忙。在前面兩層的準(zhǔn)備之后,可謂萬事俱備谈喳,PublicApiFunctionalTest册烈、ThreadingTest,看名字就知道了婿禽。
5. HelpersTest 該類是個閑散人員赏僧,不依賴任何環(huán)境的模擬大猛。所以可以猜測是測試純功能函數(shù)的。
了解了大體結(jié)構(gòu)之后淀零,就需要讀源碼了挽绩。走讀一下源碼,不多驾中,大概不到1500行的樣子唉堪。然后就可以拿到大體上每個類都做了什么,如下:
1. AbstractDownloadProviderFunctionalTest 是基礎(chǔ)抽象類肩民,這里完成了context唠亚、systemFacade、server持痰、contentResolver等基礎(chǔ)環(huán)境的假冒偽劣活動灶搜,同時提供了偽造服務(wù)器響應(yīng)的方法供子類使用;
2. AbstractPublicApiTest 是上面那位的子類共啃,同樣是抽象的,這里封裝了以DownloadID為核心的內(nèi)部類Download供后續(xù)斷言使用暂题;引入了DownloadManager的工具實體移剪,同時提供了偽造客戶端請求的各種方法供子類使用;
3. DownloadProviderFunctionalTest 繞開了對DownloadManager的測試薪者,它使用暴力插入數(shù)據(jù)庫的方法添加下載纵苛,單純的測試下載器的功能,所以它只繼承了①言津;
4. PublicApiFunctionalTest 主要是針對DownloadManager的功能api測試攻人,這里模擬了各種各樣的下載環(huán)境,實現(xiàn)了各種網(wǎng)絡(luò)情況下的功能單元測試悬槽;
5. ThreadingTest 主要針對頻繁開下載服務(wù)的特殊情況進(jìn)行測試怀吻;
6. HelpersTest 則是比較獨(dú)立的測試,測試/module/DownloadSystem 中Util包??Helpers 工具類中的方法初婆;
好蓬坡。最后我們回到剛開始的那幾個問題。通過類圖解析和代碼走讀大概就能得到答案磅叛。
其一屑咳,android junit框架提供了對android service的測試支持,上面的所有測試類都是基于ServiceTestCase 實現(xiàn)的弊琴;
其二兆龙,可以找到各種mock工具來模擬各種依賴于硬件、網(wǎng)絡(luò)的接口實現(xiàn)敲董,下載測試中使用的就是 mockwebserver.jar紫皇,來模擬服務(wù)器慰安、響應(yīng);
其三坝橡,測試代碼也需要偽造相關(guān)的環(huán)境泻帮,context、resolver计寇,包括功能源碼將系統(tǒng)相關(guān)的信息抽象成接口锣杂,在測試的過程中測試代碼可以實現(xiàn)測試所需要的fake版本,不得不說這就是代碼可測試性良好的一個體現(xiàn)番宁,目的就是繞開或模擬任何不可預(yù)期的依賴元莫,來針對測試目標(biāo)代碼完成對邏輯的測試;
其四蝶押,對于各種網(wǎng)絡(luò)環(huán)境的測試踱蠢,實際上是通過模擬不同的服務(wù)器響應(yīng)來實現(xiàn)的,絕大部分用例都是圍繞這個思路來編寫的棋电。不過是否能覆蓋到所有情況的下載還是未知數(shù)茎截;
其五,針對一個復(fù)雜的功能系統(tǒng)來測試赶盔,整個測試代碼的架構(gòu)顯然是需要提前設(shè)計的企锌。庖丁解牛一般,一步一步把所有的環(huán)境都模擬好于未,再動手編寫各個細(xì)節(jié)點的測試用例撕攒。當(dāng)然,這與被測試的功能源碼的結(jié)構(gòu)設(shè)計烘浦、可測試性的考慮也是有關(guān)系的抖坪。這就是傳說中的設(shè)計吧,路漫漫其修遠(yuǎn)兮啊闷叉。