客戶端單元測試-Android

單元測試的作用

爲了使工作完成的更加輕鬆,設計更加的完善,減少調試的時間提高代碼的質量。

什麼是單元測試

單元測試是開發者編寫的一小段代碼,用於檢驗被測代碼的一個很小的、很明確的功能是否正確,通常而言,一個單元測試是用於判斷某個特定條件(或者場景)下某個特定函數的行爲。

Android 端的單元測試

什麼是mvp

  -->區分mvc,mvp,mvvm

關於單元測試

對於單元測試需要了解

  • Android Studio的test和AndroidTest
  • AndroidJUnitRunner:一個兼容Junit4的Andriod單元測試框架
  • Mockito:單元測試利器
  • Espresso:支持UI測試的單元測試框架

MVP各層的單元測試選型

在項目中,MVP各層所使用的單元測試框架如下圖所示:

             

  • P層:不需要任何Android環境,因此使用Junit測試即可
  • V層:使用Google強大的Espresso進行UI的測試
  • M層:涉及到數據庫相關操作,因此需要依賴Android環境,使用AndroidJUnitRunner進行測試

各層的配合測試

推薦谷歌官方mvp實例項目  https://github.com/googlesamples/android-architecture

接下來我們以TO-DO List頁面(TasksActivity/TaskFragment)中加載任務列表功能爲例,此場景的功能界面如下圖所示:

                     blob.png

P層測試

P層在這裏就只做了loadTask()事情

                  blob.png

                                                          loadTask()時序圖

從圖中看loadTask()執行邏輯,

1.調用V層開啓加載框 -->2.調用M層獲取列表數據 --> 3.M層以回調模式返回數據 -->4.調用V層關閉加載框 --> 5.調用v層顯示列表數據

這5個步驟裏面,每個步驟的邏輯是否精準是V層和M層需要測試的,對於P層來說,它只需要確認這5個步驟如期調用就行.

這裏使用mockito,在測試類TasksPresenterTest中


總結:讓Presenter充當個合格的皮條客,去調用其他兩層的邏輯,在假設其他兩層代碼邏輯都是正確的前提下,做一些mock測試,儘可能覆蓋所有邏輯路徑。

V層的測試

對於V層在加載任務列表中的邏輯就只有顯示加載框-->隱藏加載框 →顯示列表數據

既然這麼簡單那麼我們驗證添加任務到顯示任務列表

流程:點擊添加按鈕-->打開軟鍵盤輸入標題和描述-->保存代辦任務-->返回任務列表--> 驗證輸入的代辦任務是否存在

通過Espresso可以模擬這些步驟,並進行驗證。這個測試類是TasksScreenTest

1.首先是添加任務和輸入標題描述,保存代辦任務

                   

2.返回任務列表就需要刷新列表–其實也就是刷新數據–相當於點擊選擇all標籤

                  

 

3.驗證剛剛的任務是否存在

                 

 

整個V層測試方法:

                 

 

總結:Espresso好強大,V層測試是站在用戶角度去測試每一個操作,它也不止測試了V層,還測試了一部分的P層和M層

M層測試

關於Model層的測試,首先要了解下該項目中,model層的設計,類層次如下圖所示:

               blob.png

  • TasksLocalDataSource:負責本地數據庫增刪改查操作

  • TasksRemoteDataSource:負責網絡請求(該項目中用handler.postDelayed()延時來模擬網絡請求)

  • TasksRepository:相當於整個Model層的門面,根據邏輯判斷決定數據來自於本地數據庫或是網絡。Presenter層只與它打交道。

根據以上分析,可見對Model層的測試要完整的覆蓋這三個類。

1.我們先看門面TasksRepository的測試,先看看這個類中有關獲取待辦任務列表的流程圖:

                             

所以對於TasksRepository來講,測試的內容主要是驗證1,2,3的邏輯是否在相應的輸入下覆蓋到位,對於1,2,3的數據準確性無需關心,

由各自DataSource去驗證,因此它的測試與Android環境無關,用Junit+Mockito測試。要完整覆蓋的話,需要多個測試case,

篇幅有限,這裏只講第2種。這個測試類是TasksRepositoryTest,代碼如下:

                

 

 

2.接下來是是TasksLocalDataSource的測試。該測試與數據庫有關,因此依賴於Android環境,且要驗證數據存取的準確性,

因此需要做一些斷言,使用AndroidJUnitRunner進行測試,這個類是TasksLocalDataSourceTest,代碼如下:

               

 

3.最後來看看跟網絡請求相關的TasksRemoteDataSource的測試

Google並沒有對這個類本身進行測試,但是對其他層依賴網絡請求數據進行測試的場景做了支持。試想一下,通過上面的分析,

我們知道View層是真刀真槍的在模擬用戶的操作進行測試,如果某個測試case需要發起網絡請求,此時我們不知道何時才能返回數據,

且由於網絡狀況等原因可能導致請求失敗,種種不確定因素下,是不可能完成一個測試的,解決的辦法很簡單,

就是對網絡請求進行Fake,這個類是FakeTasksRemoteDataSource,原理便是當需要用到TasksRemoteDataSource時,

不會真正使用該類,而是注入FakeTasksRemoteDataSource,返回事先定義好的數據。

mvp單元測試總結

MVP各層之間的職責以及對應的測試內容,接下來做個總結,MVP測試架構圖

           

View層

職責:MVP模式下,View層終於揚眉吐氣了,View本身該做的事情都能做了,比如UI佈局,數據渲染,點擊按鈕交互等等

測試方式:以正常小QA的測試思維方法,就可以來定義這一層的測試方式,測試過程中需要真機或模擬器,並做真實的操作。

測試選型:依賴於Android環境,用谷歌強大的Espresso+AndroidJUnitRunner,Espresso用於模擬和驗證各種各樣的UI操作,代碼存放於AndroidTest中。

Presenter層:

職責:這一層是拉皮條的,負責M和V層的對接,所以有較少的處理輸入輸出的機會,他只用來控制邏輯,去調用相應的Model和View的邏輯。

測試選型:他的職責決定了他很少去斷言輸入輸出,測試邏輯覆蓋的路徑是否正確即可,因此他與Android環境無關,用Junit+Mockito測試即可,代碼存放於test中。

Model層

職責:負責數據的存取,數據可能來自於網絡、數據庫和內存

數據庫增刪改查:需測試數據存取的準確性,依賴Android環境進行測試,因此使用AndroidJUnitRunner,代碼存放於androidTest中

網絡請求:不測試真實的網絡請求,但提供了Fake供其他層調用測試。

封裝的門面類:決定了數據的來源和去向是來自於本地數據庫 or 網絡 or 內存,此爲真正對其他層暴露的Model類。此類不做數據準確性的驗證,只做mock測試,驗證覆蓋路徑。

                         UT選型Junit+Mockito,代碼存放於test中。

總結

寫單元測試前期雖然比較複雜和麻煩,但是這樣谷歌官方的寫法思路是非常清晰的,非常值得學習,可以減少很多測試成本,減少錯誤率。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章