iT邦幫忙

第 11 屆 iThome 鐵人賽

DAY 13
0
Mobile Development

從0開始,全方面自動化測試Android App系列 第 13

[Day 13] TDD 測試驅動開發模式介紹

當我們把unit test一些基本概念弄清楚後,我們進入下一個章節TDD,TDD全名是Test Driven Development,也就是測試導向開發,在還沒寫production code之前先寫測試,聽起來很難想像因為跟我們的開發習慣大異其趣。都還沒有開始寫code是要怎麼先測試呢?其實並會不太難,只要改一下寫code的習慣先看spec規畫interface再來寫production code就可以了。

MVP應用

開發需求:在Main page中的TextView中顯示username欄位,文字屬性16dp,置中,顏色黑色。

假設有一個開發需求如上。這時候尋常的做法就是打開designer的UI圖第一步先把layout檔建立好,然後下一步就在Activity或Fragment裡面寫一個跟server reqeust的function去更新TextView。這個做法很平常,但是如果我們實踐TDD的測試導向開發方法,我們把重點擺在正確的邏輯先寫出來再去寫UI部份,因為UI可能不斷的改變,邏輯可能一確定下來就不會變了(可能啦)。

我建議可以這樣做。第一步,先不要寫layout部份,layout只是先讓自己有一個畫面感覺,先試著把跟UI有關及無關的東西分開來,像是要對TextView操作setText這就是UI有關的部份,而跟server request data的部份就跟UI無關,因為之前說過Unit test無法測試跟UI元件instance有關的部份。

不用管細節實作,先開發介面吧

所以我們單元測試的重點就擺在UI無關的server requst部份。如果採用MVP架構的話,我們要測試的目標就是presenter的function,下一步就是建立一個presenter class把跟server有關的邏輯寫在裡面,在忍不住想要開始寫production code之前先等等,我們再回去看之前的範例,你有沒有發現我們在做單元測試的時候其實都會把presenter裡面用到的物件mock起來,被mock起來的物件其中要怎麼return value或行為都是由該測試單元來定義而不是真的去執行Activity的細節來獲得資訊,也就是在寫測試code的時候不用管presenter細節的實作,我們只要知道function名稱跟回傳型態就可以寫測試的code了,這樣講是不是比較有感覺了。

https://ithelp.ithome.com.tw/upload/images/20190927/20120975iMLkuKjfAv.png

此時我們把TDD的流程畫成上圖,可分為三個階段

  • 需求轉換
    先想到UI會跟presenter要求資料,所以我們建立一個presenter的empty function叫requestUserName()用來給Activity呼叫。然後當reqeust資料完成後會需要更新UI,所以我們也建立一個function叫receivedUserName()通知Activity。

  • 單元測試
    這個時候就可以開始寫測試程式了,如同我們的範例一樣,當presenter執行requestUserName()的時候UI interface的receivedUserName要被呼叫到。直到這邊我們的還不需要有任何production code的加入就已經驗證好這個需求的邏輯了。

  • 細節開發
    單元測試完成後我們再來寫production code,你就會發現開發這個task的必要步驟已經寫好了,我的production code只要依照這些步驟來寫就好了,寫完再去執行測試就可以對照我們的production code是否有遵循unit test裡的規則來寫。

MVVM應用

取得user清單並且在Main page上filter出first name是Daniel的user

同理我們也可以用之前在MVVM章節提過的範例來討論,PM開了一個task要把server取得的user list找出firstName是Daniel的清單顯示在Activity裡,我們一樣在ViewModel的class裡先依照這個要求建立一個private的LiveData叫users,然後用一個public getter把他包起來供外部呼叫使用。然後針對server reqeust的部份我們用一個Sever class把server reqeust介面化,當呼叫requestUsers()我們就要回傳user list,最後在ViewModel用之前提過的DIP觀念用setter的方式把Server實體放入ViewModel。針對task要求這樣unit test的interface都建立好了。然後我們就可以先寫unit test如範例所述。到這個時間點我們都還沒開始寫ViewModel裡users變數裡實作的production code喔。

https://ithelp.ithome.com.tw/upload/images/20190927/20120975dvVOA5TpTL.png

最後跟上述MVP TDD流程提到的一樣,才開始去實作ViewModel裡的細節。有發現了嗎,此時不管你production code怎麼寫都須要通過這個unit test的測試,mock的測試資料已經放了3個user data但是只能顯示一個。
所以說TDD沒想像的複雜,但的確需要一點耐心來完成。一開始會花你很多時間,但如果你的code在開發時需要refactor的話,利用TDD會幫你省下許多debug時間。我們可以看下圖,我們不論是第一次開發或是refacoring重構都可以一直follow這個流程開發完立刻單元測試減少出錯機會。

https://ithelp.ithome.com.tw/upload/images/20190927/20120975xcPjNRf4q5.png

結論

有人可能會覺得這樣的好處是什麼?就只是聽起來比較厲害而已嗎?先寫test case和開發完再來寫test case這差在哪?我本身經驗規納出以下兩點

  • 驗證開發環節
    當你先寫test case的時候你會去針對task的每個細節都想過一遍(不然你要怎麼寫)並驗證正確性,不會說寫production code邊寫邊問PM說這個要求有問題再來改,改test case遠比改production code快,所以在你寫production code前你已經非常了解整個細節,寫起來就像piece of cake。
  • 分工合作,加快進度
    還有另一個好處是當開發時程較趕的話,可以一個人先寫test case,因為task的細節已經被驗證過了等於有一個Spec,一個人再依照這個可被單元測試驗證的Spec來開發。

下一個章節我們來介紹TDD的加強版BDD(Behavior Driven Development)。


上一篇
[Day 12] 單元測試的選擇 MVP vs MVVM
下一篇
[Day 14] BDD 開發模式介紹
系列文
從0開始,全方面自動化測試Android App30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言