單元測試搞了一段時間,發現網上不少關於單元測試的文章都是講了概念,講了框架的使用,但對於一個實際的項目的操做,由於項目的複雜性,框架的穩定性等,確每每沒法進行。本篇博客從實際出發,基於實際的項目總結而出。java
本系列文章不會涉及到單元測試的概念,以及它的各類現實意義。僅從實現入手,關於它的優劣不作分析。android
單元測試系列會分爲三篇博客:架構
Powermock
的Android單元測試經常使用方法指南Cobertra
&sonarqube
的單元測試覆蓋率統計Google
官方文提供了單元測試的支持。在建立項目的時候會默認建立test
和androidTest
目錄。分別是單元測試和集成測試。單元測試是對方法的測試,粒度較小,無需運行在真機上。集成測試須要每次運行須要跑在真機上,粒度較大,運行時間較長,並且不利於一些自動化的工做。app
本系列的核心從單元測試入手,以自動化爲目的。框架
單元測試一個繞不開的話題就是對於android.jar
的問題。因爲android.*
的官方類,在運行單元測試的時候,只有方法的聲明,內部的全部方法都會throw new RuntimeException('Stub')
。那麼一旦有調用官方類的地方,好比View
,Intent
,Activity
等,就會報錯,致使單元測試沒法執行。jvm
一種常見的解決方式是經過架構來解決,將一些代碼邏輯和官方類解耦,好比MVP
,對Presenter
作測試,由於大部分邏輯都在Presenter
,因此還ok。ide
可是不幸的,通常搞單元測試的時候,很難是從一個新項目入手的,架構很難變更,一旦修改架構,影響範圍比較廣。單元測試
而咱們的項目就是這樣的,全部的邏輯都在Activity
中編寫,一旦測試邏輯就確定繞不開官方類。測試
官方文檔上提到了單元測試的兩種解決方案。spa
一種是經過Mock
來解決,及將官方類的調用方法給代理一下,不會實際的調用官方類的相關方法。
另一種是Robolectric
,該框架經過在jvm
上模擬android
虛擬機,以單元測試的方式來完成集成測試。
Robolectric
(放棄)由於最終沒有使用這個框架,因此先介紹一下這個框架。
該框架至關因而搭建了一個android
虛擬機,其運行單元測試的時候,實質是運行了一個app
。那麼其作測試的邏輯更傾向於appium
等的UI
測試,查詢一個控件,模擬點擊,驗證邏輯。
由於其模擬的虛擬機,那麼他對官方的方法作了擴展,提供了一些列的ShadowXXX
類,便於作驗證和模擬。好比獲取當前彈出的dialog
,最後一個彈出的toast
等等。
調研的時候,該框架最新版本爲4.3
,而且從4.0
開始,已經開始和官方的androidx.test
下測試庫進行兼容。能夠經過官方espresso
完成一些列操做。那麼一套代碼,技能在控制檯運行,又能在模擬器上運行,想一想仍是挺美好的。
可是 !!!
由於咱們的項目都是在Activity
裏面寫的,一些業務邏輯都是使用私有方法,那麼相對私有方法作驗證,經過查詢控件和經過UI
的展現來驗證邏輯的正確與否,十分的複雜。
舉個例子:
@Override
public void onClick(View v) {
switch (v.getId()) {
case R.id.skip:
startNextActivity(false);
break;
case R.id.splash_image:
startNextActivity(true);
break;
default:
break;
}
}
private synchronized void startNextActivity(boolean isClick) {}
複製代碼
我想驗證不一樣的View
點擊,調用的startNextActivity
的參數是否正確。若是從UI
上驗證十分的複雜,並且萬一startNextActivity
的內部邏輯有問題,或者比較巧妙,那麼UI
的驗證也不必定準確。
有方法解決嗎??確定有,即是Mock
,這個後面會說。
可以Mock
私有方法的經常使用的是Powermock
,可是!!!!!
該框架和Robolectric
存在着各類兼容問題,在我頭髮掉了一地以後,也沒有解決。
因此放棄了!!!!注意是放棄了Robolectric
!!!!
mock
是單元測試中經常使用的一種方式,經過對即將調用方法的修改,模擬調用方法的返回值等等,具體的概念百度上一大堆。我就再也不這裏廢話了。
官方文檔上建議使用Mockito
完成mock
操做,可是該庫不支持靜態方法,私有方法,final
等的mock
。
上面提到了Powermock
,他提供更增強大的mock
功能,並且它提供了Mockito
的支持,使用上和Mockito
基本上同樣。
好比說,對於上面的代碼,使用Powermock
方法驗證邏輯以下:
@Test
public void onClickSkip() throws Exception {
// mock activity, activity的全部方法都不會被執行
LauncherActivity activity = PowerMockito.mock(LauncherActivity.class);
// 指定activity的onClick不被`mock,調用真實的邏輯,以便進行單元測試
PowerMockito.doCallRealMethod().when(activity, "onClick", ArgumentMatchers.any(View.class));
// Mock 官方類
View view = PowerMockito.mock(View.class);
// 指定getId的返回值
PowerMockito.doReturn(R.id.skip).when(view, "getId");
// 調用測試的方法
activity.onClick(view);
// 驗證指定的方法和參數是否被滴啊用
PowerMockito.verifyPrivate(activity).invoke("startNextActivity", false);
}
複製代碼
代碼註釋很清楚,不在廢話。
按照上面的思路,其實能夠驗證大部分的單元測試邏輯。
綜上所述,決定使用Powermock
爲基礎,完成單元測試的編寫。