Android開(kāi)發(fā)筆記之:對(duì)實(shí)踐TDD的一些建議說(shuō)明
更新時(shí)間:2013年05月21日 09:29:48 作者:
本篇文章是對(duì)Android中實(shí)踐TDD的一些建議進(jìn)行了詳細(xì)的分析介紹,需要的朋友參考下
最近部分采用了TDD的方法來(lái)開(kāi)發(fā)一個(gè)模塊,小有收獲特此總結(jié)一下:
1. TDD的基本原則
TDD的最核心思想就是先明確需求,且用代碼的方式量化,明確需求標(biāo)準(zhǔn),然后進(jìn)行編碼實(shí)現(xiàn)以達(dá)成由代碼測(cè)試來(lái)衡量的標(biāo)準(zhǔn)。
那么它要求,先把需要標(biāo)準(zhǔn)寫(xiě)出來(lái),每次只寫(xiě)一個(gè)。編碼實(shí)現(xiàn)通過(guò)達(dá)到,并剛好滿足這個(gè)標(biāo)準(zhǔn)。這樣一點(diǎn)一點(diǎn)的迭代。
這樣有三個(gè)好處:一個(gè)是先明確標(biāo)準(zhǔn),不至于我們迷失主題,偏離方向。有標(biāo)準(zhǔn)在檢測(cè),保證代碼是正確的。僅滿足當(dāng)前測(cè)試,不至于過(guò)早優(yōu)化和過(guò)度設(shè)計(jì)。
2. TDD的難點(diǎn)
難點(diǎn)在于如何設(shè)計(jì)這個(gè)測(cè)試標(biāo)準(zhǔn),
1)讓它足夠小,是一個(gè)需求單元;
2)成為標(biāo)準(zhǔn),也就是如何檢測(cè)正確性;
3)就是如何在最大程度模擬真實(shí)運(yùn)行的場(chǎng)景,而不是為了測(cè)試而寫(xiě)出許多額外的工具,也就是說(shuō)測(cè)試應(yīng)該跟真實(shí)的項(xiàng)目代碼一樣,不應(yīng)該有多余的東西。
這關(guān)鍵在于要分析挖掘需求,并細(xì)化需求。如果都像書(shū)中的例子那樣測(cè)試一些API那倒是很好寫(xiě),因?yàn)闇y(cè)試代碼跟真實(shí)的App代碼用一樣的方式來(lái)調(diào)用API,而且API的功能也會(huì)有明確的描述。但現(xiàn)實(shí)情況并非如此,比如很多框架就很難測(cè)試,很多對(duì)象和創(chuàng)建和控制都是由框架來(lái)做,你無(wú)法像控制。這就導(dǎo)致了很難寫(xiě)測(cè)試用例。
還有就是多線程,由于線程帶來(lái)的不確定性,有很多偽失敗,這可以參考書(shū),書(shū)中有方法。
3. Android中的TDD
老實(shí)說(shuō),在Android完全用TDD的方法來(lái)開(kāi)發(fā)是不可能的。原因如下:
1. Android中的應(yīng)用程序主要結(jié)構(gòu)是四大組件:Service,Activity和Provider和Receiver這四東西的創(chuàng)建和銷毀都是由框架來(lái)控制。所以你不可能像書(shū)中例子那樣去測(cè)試它們,因?yàn)橛行┫拗谱屇銦o(wú)法用代碼來(lái)測(cè)試。
2. 有些東西是系統(tǒng)框架的回調(diào)或者很基本東西根本不用寫(xiě)TestCase。比如View的Click/LongClick/Touch事件的處理之類的,或者Activity的生命周期回調(diào),或者OptionsMenu/ContextMenu之類的。
3. SDK中的用于測(cè)試的API功能太弱
這就導(dǎo)致了,為了測(cè)試一個(gè)小功能需要做很多工作和寫(xiě)很多代碼,遠(yuǎn)大于直接實(shí)現(xiàn)。比如測(cè)試一個(gè)彈出的Dialog,如果直接實(shí)現(xiàn)很容易;但如果用代碼來(lái)測(cè)試就要多3,4倍的工作量,遠(yuǎn)大于直接實(shí)現(xiàn)。
4. 那么在Android中應(yīng)該如何運(yùn)用好TDD呢?以下是一些建議:
1. 使用Robotium
這是強(qiáng)大的工具,它比SDK中的東西可是方便的很多比如searchText,clickMenu之類的接口非常的方便和實(shí)用。
2. 自動(dòng)測(cè)試+手動(dòng)測(cè)試
同樣要遵循原則,但是對(duì)于測(cè)試用例,沒(méi)有必要完全用代碼來(lái)寫(xiě),可以部分手動(dòng)測(cè)試:一般的原則來(lái)講如果自動(dòng)測(cè)試比較方便的實(shí)現(xiàn)就寫(xiě)TestCase,如果手動(dòng)測(cè)試很方便就手動(dòng)測(cè)試,這沒(méi)有死規(guī)則要看具體的情況。
比如,View的事件,Activity的事件,Activity的Menu,Dialog之類的與交互相關(guān)的東西,以及跨應(yīng)用交互的用例最好手動(dòng)來(lái)測(cè)試,因?yàn)檫@些東西用代碼來(lái)測(cè)試更麻煩。
但對(duì)于一些涉及數(shù)值,計(jì)算,量化等就用代碼來(lái)做。比如下載一個(gè)文件,設(shè)定好路徑后就可以直接用File對(duì)象來(lái)檢測(cè)文件是否下載成功。
3. Provider必須要測(cè)試
Provider提供的是API,它非常好測(cè)試也容易寫(xiě),又是一個(gè)項(xiàng)目的基本設(shè)施,所以必須要好好測(cè)試,否則如果在Activity上某條數(shù)據(jù)有問(wèn)題,你必須要確定是顯示上出了問(wèn)題還是Provider里出了問(wèn)題。通常CRUD必須測(cè)試,還有就是where語(yǔ)句,以及逆向測(cè)試,必須要檢測(cè)Uri的合法性等,還有就是要檢測(cè)對(duì)特殊字符的處理,比如'和"。
4. 除Service和Activity以外的東西,特別是自己實(shí)現(xiàn)的類似API的類,如果里面涉及一些業(yè)務(wù)邏輯也要進(jìn)行測(cè)試。這就跟書(shū)中的例子差不多了,測(cè)試的難易成就也取決于業(yè)務(wù)的分解,設(shè)計(jì)和耦合度了。
5. 用反射來(lái)測(cè)試類的內(nèi)部
對(duì)于Service和Activity雖然可以在TestCase中拿到它的實(shí)例,但是Service和Activity是一個(gè)組件單元在實(shí)際中并不會(huì)Public太多的接口,它們是處于最頂端的調(diào)用其他接口,而自己不會(huì),也不應(yīng)該公開(kāi)接口給別人用,原因就是它們的創(chuàng)建和生命周期的管理都是由系統(tǒng)控制的,別處不應(yīng)該有太多對(duì)它們的引用。
那么當(dāng)要測(cè)試Service和Activity內(nèi)部時(shí)怎么辦呢?比如要測(cè)試某個(gè)Service內(nèi)部的一個(gè)int[] mPlaylistQueue。我們總不能為了寫(xiě)Case而在Service中加接口吧!這時(shí)就要用反射機(jī)制來(lái)取出這個(gè)成員的實(shí)例,然后檢查它的數(shù)據(jù)。
6. 有些東西必須手動(dòng)測(cè)試,自動(dòng)化無(wú)法完成
TestCase是有特殊的Context和MockObject的,它是對(duì)真實(shí)Android運(yùn)行的一個(gè)最大化的模擬,它并不跟應(yīng)用真正運(yùn)行時(shí)的情況完全一樣!而且由于Permission的原因,某些事情Instrumentation是無(wú)法做的,比如Alarm,日期等Instrumentation是無(wú)權(quán)限更改的。這些必須要靠手動(dòng)測(cè)試。
還有就是Service和Activity的初始化和銷毀,特別是銷毀,沒(méi)辦法測(cè)試,也就是說(shuō)對(duì)于onDestroy()里面的東西,還真的不好去測(cè)試。第一,你不知道它何時(shí)被回調(diào)到;第二,執(zhí)行到它時(shí)對(duì)象快被銷毀了,你持有的引用不一定有效了;第三,成員對(duì)象是否都有效也無(wú)法得知。對(duì)于onDestroy只能通過(guò)調(diào)試手段手動(dòng)的去測(cè)試。
總之,在我看來(lái),TDD的核心思想是測(cè)試先來(lái),實(shí)現(xiàn)后來(lái)。但如何測(cè)試并沒(méi)有列規(guī)定非要用代碼,所以根據(jù)實(shí)際情況,選擇最佳的測(cè)試手段。
1. TDD的基本原則
TDD的最核心思想就是先明確需求,且用代碼的方式量化,明確需求標(biāo)準(zhǔn),然后進(jìn)行編碼實(shí)現(xiàn)以達(dá)成由代碼測(cè)試來(lái)衡量的標(biāo)準(zhǔn)。
那么它要求,先把需要標(biāo)準(zhǔn)寫(xiě)出來(lái),每次只寫(xiě)一個(gè)。編碼實(shí)現(xiàn)通過(guò)達(dá)到,并剛好滿足這個(gè)標(biāo)準(zhǔn)。這樣一點(diǎn)一點(diǎn)的迭代。
這樣有三個(gè)好處:一個(gè)是先明確標(biāo)準(zhǔn),不至于我們迷失主題,偏離方向。有標(biāo)準(zhǔn)在檢測(cè),保證代碼是正確的。僅滿足當(dāng)前測(cè)試,不至于過(guò)早優(yōu)化和過(guò)度設(shè)計(jì)。
2. TDD的難點(diǎn)
難點(diǎn)在于如何設(shè)計(jì)這個(gè)測(cè)試標(biāo)準(zhǔn),
1)讓它足夠小,是一個(gè)需求單元;
2)成為標(biāo)準(zhǔn),也就是如何檢測(cè)正確性;
3)就是如何在最大程度模擬真實(shí)運(yùn)行的場(chǎng)景,而不是為了測(cè)試而寫(xiě)出許多額外的工具,也就是說(shuō)測(cè)試應(yīng)該跟真實(shí)的項(xiàng)目代碼一樣,不應(yīng)該有多余的東西。
這關(guān)鍵在于要分析挖掘需求,并細(xì)化需求。如果都像書(shū)中的例子那樣測(cè)試一些API那倒是很好寫(xiě),因?yàn)闇y(cè)試代碼跟真實(shí)的App代碼用一樣的方式來(lái)調(diào)用API,而且API的功能也會(huì)有明確的描述。但現(xiàn)實(shí)情況并非如此,比如很多框架就很難測(cè)試,很多對(duì)象和創(chuàng)建和控制都是由框架來(lái)做,你無(wú)法像控制。這就導(dǎo)致了很難寫(xiě)測(cè)試用例。
還有就是多線程,由于線程帶來(lái)的不確定性,有很多偽失敗,這可以參考書(shū),書(shū)中有方法。
3. Android中的TDD
老實(shí)說(shuō),在Android完全用TDD的方法來(lái)開(kāi)發(fā)是不可能的。原因如下:
1. Android中的應(yīng)用程序主要結(jié)構(gòu)是四大組件:Service,Activity和Provider和Receiver這四東西的創(chuàng)建和銷毀都是由框架來(lái)控制。所以你不可能像書(shū)中例子那樣去測(cè)試它們,因?yàn)橛行┫拗谱屇銦o(wú)法用代碼來(lái)測(cè)試。
2. 有些東西是系統(tǒng)框架的回調(diào)或者很基本東西根本不用寫(xiě)TestCase。比如View的Click/LongClick/Touch事件的處理之類的,或者Activity的生命周期回調(diào),或者OptionsMenu/ContextMenu之類的。
3. SDK中的用于測(cè)試的API功能太弱
這就導(dǎo)致了,為了測(cè)試一個(gè)小功能需要做很多工作和寫(xiě)很多代碼,遠(yuǎn)大于直接實(shí)現(xiàn)。比如測(cè)試一個(gè)彈出的Dialog,如果直接實(shí)現(xiàn)很容易;但如果用代碼來(lái)測(cè)試就要多3,4倍的工作量,遠(yuǎn)大于直接實(shí)現(xiàn)。
4. 那么在Android中應(yīng)該如何運(yùn)用好TDD呢?以下是一些建議:
1. 使用Robotium
這是強(qiáng)大的工具,它比SDK中的東西可是方便的很多比如searchText,clickMenu之類的接口非常的方便和實(shí)用。
2. 自動(dòng)測(cè)試+手動(dòng)測(cè)試
同樣要遵循原則,但是對(duì)于測(cè)試用例,沒(méi)有必要完全用代碼來(lái)寫(xiě),可以部分手動(dòng)測(cè)試:一般的原則來(lái)講如果自動(dòng)測(cè)試比較方便的實(shí)現(xiàn)就寫(xiě)TestCase,如果手動(dòng)測(cè)試很方便就手動(dòng)測(cè)試,這沒(méi)有死規(guī)則要看具體的情況。
比如,View的事件,Activity的事件,Activity的Menu,Dialog之類的與交互相關(guān)的東西,以及跨應(yīng)用交互的用例最好手動(dòng)來(lái)測(cè)試,因?yàn)檫@些東西用代碼來(lái)測(cè)試更麻煩。
但對(duì)于一些涉及數(shù)值,計(jì)算,量化等就用代碼來(lái)做。比如下載一個(gè)文件,設(shè)定好路徑后就可以直接用File對(duì)象來(lái)檢測(cè)文件是否下載成功。
3. Provider必須要測(cè)試
Provider提供的是API,它非常好測(cè)試也容易寫(xiě),又是一個(gè)項(xiàng)目的基本設(shè)施,所以必須要好好測(cè)試,否則如果在Activity上某條數(shù)據(jù)有問(wèn)題,你必須要確定是顯示上出了問(wèn)題還是Provider里出了問(wèn)題。通常CRUD必須測(cè)試,還有就是where語(yǔ)句,以及逆向測(cè)試,必須要檢測(cè)Uri的合法性等,還有就是要檢測(cè)對(duì)特殊字符的處理,比如'和"。
4. 除Service和Activity以外的東西,特別是自己實(shí)現(xiàn)的類似API的類,如果里面涉及一些業(yè)務(wù)邏輯也要進(jìn)行測(cè)試。這就跟書(shū)中的例子差不多了,測(cè)試的難易成就也取決于業(yè)務(wù)的分解,設(shè)計(jì)和耦合度了。
5. 用反射來(lái)測(cè)試類的內(nèi)部
對(duì)于Service和Activity雖然可以在TestCase中拿到它的實(shí)例,但是Service和Activity是一個(gè)組件單元在實(shí)際中并不會(huì)Public太多的接口,它們是處于最頂端的調(diào)用其他接口,而自己不會(huì),也不應(yīng)該公開(kāi)接口給別人用,原因就是它們的創(chuàng)建和生命周期的管理都是由系統(tǒng)控制的,別處不應(yīng)該有太多對(duì)它們的引用。
那么當(dāng)要測(cè)試Service和Activity內(nèi)部時(shí)怎么辦呢?比如要測(cè)試某個(gè)Service內(nèi)部的一個(gè)int[] mPlaylistQueue。我們總不能為了寫(xiě)Case而在Service中加接口吧!這時(shí)就要用反射機(jī)制來(lái)取出這個(gè)成員的實(shí)例,然后檢查它的數(shù)據(jù)。
6. 有些東西必須手動(dòng)測(cè)試,自動(dòng)化無(wú)法完成
TestCase是有特殊的Context和MockObject的,它是對(duì)真實(shí)Android運(yùn)行的一個(gè)最大化的模擬,它并不跟應(yīng)用真正運(yùn)行時(shí)的情況完全一樣!而且由于Permission的原因,某些事情Instrumentation是無(wú)法做的,比如Alarm,日期等Instrumentation是無(wú)權(quán)限更改的。這些必須要靠手動(dòng)測(cè)試。
還有就是Service和Activity的初始化和銷毀,特別是銷毀,沒(méi)辦法測(cè)試,也就是說(shuō)對(duì)于onDestroy()里面的東西,還真的不好去測(cè)試。第一,你不知道它何時(shí)被回調(diào)到;第二,執(zhí)行到它時(shí)對(duì)象快被銷毀了,你持有的引用不一定有效了;第三,成員對(duì)象是否都有效也無(wú)法得知。對(duì)于onDestroy只能通過(guò)調(diào)試手段手動(dòng)的去測(cè)試。
總之,在我看來(lái),TDD的核心思想是測(cè)試先來(lái),實(shí)現(xiàn)后來(lái)。但如何測(cè)試并沒(méi)有列規(guī)定非要用代碼,所以根據(jù)實(shí)際情況,選擇最佳的測(cè)試手段。
您可能感興趣的文章:
- 淺談測(cè)試驅(qū)動(dòng)開(kāi)發(fā)TDD之爭(zhēng)
- QUnit jQuery的TDD框架
- SpringBoot內(nèi)置tomcat調(diào)優(yōu)測(cè)試優(yōu)化
- SpringBoot+redis配置及測(cè)試的方法
- SpringBoot對(duì)Controller進(jìn)行單元測(cè)試的實(shí)現(xiàn)代碼 附亂碼解決方案
- 詳解SpringBoot項(xiàng)目的創(chuàng)建與單元測(cè)試
- 解決SpringBoot 測(cè)試類無(wú)法自動(dòng)注入@Autowired的問(wèn)題
- Springboot Mybatis-Plus數(shù)據(jù)庫(kù)單元測(cè)試實(shí)戰(zhàn)(三種方式)
- Springboot集成JUnit5優(yōu)雅進(jìn)行單元測(cè)試的示例
- 使用@SpringBootTest注解進(jìn)行單元測(cè)試
- SpringBoot生產(chǎn)環(huán)境和測(cè)試環(huán)境配置分離的教程詳解
- Spring Boot web項(xiàng)目的TDD流程
相關(guān)文章
Android項(xiàng)目基本結(jié)構(gòu)詳解
這篇文章主要為大家詳細(xì)介紹了Android項(xiàng)目基本結(jié)構(gòu),從最基本的內(nèi)容講起,帶你逐步進(jìn)入用C#進(jìn)行Android應(yīng)用開(kāi)發(fā)的樂(lè)園,感興趣的小伙伴們可以參考一下2016-06-06Android判斷touch事件點(diǎn)是否在view范圍內(nèi)的方法
這篇文章主要介紹了Android判斷touch事件點(diǎn)是否在view范圍內(nèi)的方法,涉及Android事件響應(yīng)與view屬性操作的相關(guān)技巧,需要的朋友可以參考下2016-03-03分享Android平板電腦上開(kāi)發(fā)應(yīng)用程序不能全屏顯示的問(wèn)題解決
在一個(gè)8寸屏的Android平板電腦上開(kāi)發(fā)應(yīng)用程序(游戲程序),開(kāi)始的時(shí)候,總是不能全屏顯示,也不知道怎么設(shè)置才可以2013-05-05Android仿音樂(lè)播放器帶進(jìn)度的播放暫停按鈕
這篇文章主要為大家詳細(xì)介紹了Android仿音樂(lè)播放器帶進(jìn)度的播放暫停按鈕,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2018-12-12Android 后臺(tái)生成長(zhǎng)圖并分享示例(非長(zhǎng)截圖)
這篇文章主要介紹了Android 后臺(tái)生成長(zhǎng)圖并分享示例(非長(zhǎng)截圖),小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2018-08-08詳解MVP模式在Android開(kāi)發(fā)中的應(yīng)用
MVP是MVC衍生而來(lái)的,很早以前就由某軟公司提出,近年來(lái)在Android應(yīng)用開(kāi)發(fā)中越來(lái)越多的被提及,越來(lái)越重要了。這篇文章主要介紹了詳解MVP模式在Android開(kāi)發(fā)中的應(yīng)用,有興趣的可以了解一下。2016-11-11Android開(kāi)發(fā)之ListView的簡(jiǎn)單用法及定制ListView界面操作示例
這篇文章主要介紹了Android開(kāi)發(fā)之ListView的簡(jiǎn)單用法及定制ListView界面操作,結(jié)合實(shí)例形式分析了Android ListView界面布局相關(guān)操作技巧,需要的朋友可以參考下2019-04-04