把所有跟Android framework的相依都用Mock去模擬及隔離,有時不見得是好的選擇。因為你不會知道在Android裝置上是不是真的可以執行。
在上一個範例SharePreference的測試,為了讓測試速度較快,我們用模擬物件來驗證Context、SharedPreference的互動,來讓這個測試能在JVM執行(如下圖)。
這一篇要來介紹另一個方法,將測試拆分為2個部分。首先,建立專門處理SharedPreference儲存資料的物件SharedPreferenceManager。所有的儲存資料都由這個類別處理。我們將寫一個Instrumented test來測試是否真的有將資料儲存進去,而非用Mock的方式。
對於原本的Repository.saveUserId
的測試,只需要知道有成功呼叫ISharedPreferenceManger
,並傳入正確的參數即可。
拆為2個測試:
Local Unit test:
測試Repository.saveUserId 與 ISharedPreferenceManager的互動
Instrumented test:
測試SharePreference是否有儲存成功。
新增SharePreferenceManager,這個類別用來統一處理SharePreference儲存資料。
在這裡新增一個saveString、getString,只要是存取字串都可以用這個Manager來處理
class SharedPreferenceManager(override val context: Context) : ISharedPreferenceManager {
private val sharedPreferenceKey = "USER_DATA"
var sharedPreference: SharedPreferences
init {
sharedPreference = context.getSharedPreferences(sharedPreferenceKey, Context.MODE_PRIVATE)
}
override fun saveString(key: String, value: String){
sharedPreference.edit().putString(key, value).commit()
}
override fun getString(key: String): String {
return sharedPreference.getString(key, "")
}
}
有了SharedPreferenceManager,Repository就可以直接呼叫SharedPreferenceManager來儲存使用者帳號。
class Repository(val sharedPreferenceManager: ISharedPreferenceManager) {
fun saveUserId(id: String) {
sharedPreferenceManager.saveString("USER_ID", id)
}
}
驗證Repository是否有呼叫SharedPreferenceManager.saveString()
@Test
fun saveUserId() {
val mockSharedPreferenceManager = mock(ISharedPreferenceManager::class.java)
val userId = "A1234567"
val preKey = "USER_ID"
val repository = Repository(mockSharedPreferenceManager)
//Act 呼叫repository.saveUserId()
repository.saveUserId(userId)
//Assert
verify(mockSharedPreferenceManager).saveString(preKey, userId)
}
在Instrumented Test,就直接測試SharedPreference
是否有儲存資料成功。
@RunWith(AndroidJUnit4::class)
class SharedPreferenceManagerTest {
@Test
fun useAppContext() {
// Context of the app under test.
val appContext = InstrumentationRegistry.getTargetContext()
val key = "User_Id"
val value = "A123456789"
val sharedPreferenceManager: ISharedPreferenceManager = SharedPreferenceManager(appContext)
sharedPreferenceManager.saveString(key, value)
val valueFromSP = sharedPreferenceManager.getString(key)
//將SharedPreference取出,驗證結果
Assert.assertEquals(value, valueFromSP)
}
}
執行測試,你可以看到Android studio會開啟模擬器或手機,表示這是一個Instrumented test。雖然這樣的測試較花時間,但我們已提出SharedPreferenceManager來處理所有的SharedPreference儲存資料,如果有別的欄位要儲存時,事實上是不需要再異動SharedPreferenceManger,也不需要新增額外的Android test。
不是遇到Android framework,就一定是用mock來處理。
以這個範例,只有SharedPreferenceManager我們需要用Instrumented test
。在Repository我們改成了呼叫ISharedPreferenceManager這個介面,所以Repository仍可以用Unit test
的方式來測試是否與Interface有正確的互動,也就是有呼叫saveString及傳送的參數也是正確。
在你的App中,你可能會經常使用SharedPreference來存取資料。在Repository我們保留Local Unit test來提高測試的效率。在SharedPreferenceManager,這裡就直接使用Instrumented test,較接近真實的情況。
範例下載:
https://github.com/evanchen76/InstrumentedTestSample