如何测试具有由 android 生成的接口依赖项的 ViewModel class 作为单元测试
How do I test a ViewModel class which has an interface dependecy that is generated by android as a Unit Test
大家好,我正在尝试测试我的 ViewModel class,它依赖于数据源,我试图模拟它,但它不会工作,因为它是一个接口,我相信接口实现在运行时生成,我如何对这个 class 进行单元测试,下面是我的 ViewModel class
class LoginViewModel @ViewModelInject constructor(@ApplicationContext private val context: Context,
private val networkApi: NetworkAPI,
private val dataStore: DataStore<Preferences>)
: ViewModel() {
val clientNumber = MutableLiveData<String>()
val clientPassword = MutableLiveData<String>()
private val _shouldNavigate = MutableLiveData(false)
val shouldNavigate: LiveData<Boolean>
get() = _shouldNavigate
private val _errorMessage = MutableLiveData<String>()
val errorMessage: LiveData<String>
get() = _errorMessage
private val _activateDeviceButton = MutableLiveData(false)
val activateButton : LiveData<Boolean>
get() = _activateDeviceButton
init {
populateApiWithFakeData()
}
suspend fun authenticateUsers(): Boolean {
val clientNumber = clientNumber.value
val clientPassword = clientPassword.value
requireNotNull(clientNumber)
requireNotNull(clientPassword)
val (userExist, token) = networkApi.doesUserExist(clientNumber.toLong(), clientPassword)
if (token.isNotBlank()) storeTokenInStore(token)
return if (userExist) {
true
} else {
_errorMessage.value = "Incorrect account details. Please try again with correct details"
false
}
}
private suspend fun storeTokenInStore(token: String) {
dataStore.edit { pref ->
pref[TOKEN_PREFERENCE] = token
}
}
这是我的 ViewModel 测试 class
@Config(sdk = [Build.VERSION_CODES.O_MR1])
@RunWith(AndroidJUnit4::class)
class LoginViewModelTest{
private val context : Context = ApplicationProvider.getApplicationContext()
private val dataCentre = NetworkApImpl()
@Mock
private lateinit var dataStore: DataStore<Preferences>
@Before
fun setUpDataCenters(){
val loginData = DataFactory.generateLoginData()
for (data in loginData){
dataCentre.saveUserData(data)
}
}
@After
fun tearDownDataCenter(){
dataCentre.clearDataSet()
}
@Test
@ExperimentalCoroutinesApi
fun authenticateUser_shouldAuthenticateUsers(){
//Given
val viewModel = LoginViewModel(context, dataCentre, dataStore)
viewModel.clientNumber.value = "8055675745"
viewModel.clientPassword.value = "robin"
//When
var result : Boolean? = null
runBlocking {
result = viewModel.authenticateUsers()
}
//Then
Truth.assertThat(result).isTrue()
}
如有任何帮助,我们将不胜感激。
您可以按照 Mockito 的建议 here 将您的依赖项包装在您拥有的 class 中。这还有一个好处,那就是让您可以在以后更改存储实现,而不会影响使用它的每个视图模型。
大家好,我正在尝试测试我的 ViewModel class,它依赖于数据源,我试图模拟它,但它不会工作,因为它是一个接口,我相信接口实现在运行时生成,我如何对这个 class 进行单元测试,下面是我的 ViewModel class
class LoginViewModel @ViewModelInject constructor(@ApplicationContext private val context: Context,
private val networkApi: NetworkAPI,
private val dataStore: DataStore<Preferences>)
: ViewModel() {
val clientNumber = MutableLiveData<String>()
val clientPassword = MutableLiveData<String>()
private val _shouldNavigate = MutableLiveData(false)
val shouldNavigate: LiveData<Boolean>
get() = _shouldNavigate
private val _errorMessage = MutableLiveData<String>()
val errorMessage: LiveData<String>
get() = _errorMessage
private val _activateDeviceButton = MutableLiveData(false)
val activateButton : LiveData<Boolean>
get() = _activateDeviceButton
init {
populateApiWithFakeData()
}
suspend fun authenticateUsers(): Boolean {
val clientNumber = clientNumber.value
val clientPassword = clientPassword.value
requireNotNull(clientNumber)
requireNotNull(clientPassword)
val (userExist, token) = networkApi.doesUserExist(clientNumber.toLong(), clientPassword)
if (token.isNotBlank()) storeTokenInStore(token)
return if (userExist) {
true
} else {
_errorMessage.value = "Incorrect account details. Please try again with correct details"
false
}
}
private suspend fun storeTokenInStore(token: String) {
dataStore.edit { pref ->
pref[TOKEN_PREFERENCE] = token
}
}
这是我的 ViewModel 测试 class
@Config(sdk = [Build.VERSION_CODES.O_MR1])
@RunWith(AndroidJUnit4::class)
class LoginViewModelTest{
private val context : Context = ApplicationProvider.getApplicationContext()
private val dataCentre = NetworkApImpl()
@Mock
private lateinit var dataStore: DataStore<Preferences>
@Before
fun setUpDataCenters(){
val loginData = DataFactory.generateLoginData()
for (data in loginData){
dataCentre.saveUserData(data)
}
}
@After
fun tearDownDataCenter(){
dataCentre.clearDataSet()
}
@Test
@ExperimentalCoroutinesApi
fun authenticateUser_shouldAuthenticateUsers(){
//Given
val viewModel = LoginViewModel(context, dataCentre, dataStore)
viewModel.clientNumber.value = "8055675745"
viewModel.clientPassword.value = "robin"
//When
var result : Boolean? = null
runBlocking {
result = viewModel.authenticateUsers()
}
//Then
Truth.assertThat(result).isTrue()
}
如有任何帮助,我们将不胜感激。
您可以按照 Mockito 的建议 here 将您的依赖项包装在您拥有的 class 中。这还有一个好处,那就是让您可以在以后更改存储实现,而不会影响使用它的每个视图模型。