Issue resolved with unit tests

Took 1 hour 31 minutes
This commit is contained in:
2022-08-28 00:56:07 +01:00
parent fd4cd93f78
commit b6283340f2
5 changed files with 91 additions and 88 deletions

View File

@@ -45,7 +45,7 @@ class WidgetViewModel @Inject constructor(
return
}
if (rateIdFrom == rateIdTo) {
onError("Selected rates cannot be the same ${rateIdFrom}${rateIdTo}")
onError("Selected rates cannot be the same")
return
}
onSuccess(Unit)

View File

@@ -1,11 +1,13 @@
package com.appttude.h_mal.easycc.repository
import com.appttude.h_mal.easycc.data.network.SafeApiRequest
import com.appttude.h_mal.easycc.data.network.api.BackupCurrencyApi
import com.appttude.h_mal.easycc.data.network.api.CurrencyApi
import com.appttude.h_mal.easycc.data.network.response.ResponseObject
import com.appttude.h_mal.easycc.data.prefs.PreferenceProvider
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.data.repository.RepositoryImpl
import com.appttude.h_mal.easycc.models.CurrencyModel
import com.appttude.h_mal.easycc.utils.convertPairsListToString
import kotlinx.coroutines.runBlocking
import okhttp3.ResponseBody
@@ -22,7 +24,7 @@ import java.io.IOException
import kotlin.test.assertFailsWith
class RepositoryNetworkTest {
class RepositoryNetworkTest : SafeApiRequest() {
lateinit var repository: Repository
@@ -49,15 +51,16 @@ class RepositoryNetworkTest {
//create a successful retrofit response
val mockCurrencyResponse = mock(ResponseObject::class.java)
val re = Response.success(mockCurrencyResponse)
val currencyModel = mock(CurrencyModel::class.java)
//WHEN - loginApiRequest to return a successful response
val currencyPair = convertPairsListToString(s1, s2)
Mockito.`when`(api.getCurrencyRate(currencyPair)).thenReturn(re)
Mockito.`when`(responseUnwrap { api.getCurrencyRate(currencyPair) }.getCurrencyModel()).thenReturn(currencyModel)
//THEN - the unwrapped login response contains the correct values
val currencyResponse = repository.getDataFromApi(s1, s2)
assertNotNull(currencyResponse)
assertEquals(currencyResponse, mockCurrencyResponse)
assertEquals(currencyResponse, currencyModel)
}
@Test
@@ -74,6 +77,7 @@ class RepositoryNetworkTest {
//WHEN
val currencyPair = convertPairsListToString(s1, s2)
Mockito.`when`(api.getCurrencyRate(currencyPair)).thenAnswer { re }
Mockito.`when`(apiBackup.getCurrencyRate(s1, s2)).thenAnswer { re }
//THEN - assert exception is not null
val ioExceptionReturned = assertFailsWith<IOException> {

View File

@@ -0,0 +1,22 @@
package com.appttude.h_mal.easycc.ui
import androidx.lifecycle.MutableLiveData
import com.appttude.h_mal.easycc.utils.ViewState
abstract class BaseViewModelTest<V : BaseViewModel> {
abstract val viewModel: V?
open fun setUp() {
viewModel?.uiState?.observeForever {
when (it) {
is ViewState.HasStarted -> Unit
is ViewState.HasData<*> -> dataPost.postValue(it.data.getContentIfNotHandled())
is ViewState.HasError -> errorPost.postValue(it.error.getContentIfNotHandled())
}
}
}
var dataPost: MutableLiveData<Any> = MutableLiveData()
var errorPost: MutableLiveData<String> = MutableLiveData()
}

View File

@@ -1,17 +1,17 @@
package com.appttude.h_mal.easycc.ui.main
import android.os.Bundle
import android.util.Log
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.appttude.h_mal.easycc.data.network.response.ResponseObject
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.helper.CurrencyDataHelper
import com.appttude.h_mal.easycc.models.CurrencyModel
import com.appttude.h_mal.easycc.ui.BaseViewModelTest
import com.appttude.h_mal.easycc.utils.MainCoroutineRule
import com.appttude.h_mal.easycc.utils.observeOnce
import com.nhaarman.mockitokotlin2.doAnswer
import kotlinx.coroutines.ExperimentalCoroutinesApi
import kotlinx.coroutines.runBlocking
import org.junit.Assert.*
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNull
import org.junit.Before
import org.junit.Rule
import org.junit.Test
@@ -22,7 +22,7 @@ import org.mockito.MockitoAnnotations
import java.io.IOException
@OptIn(ExperimentalCoroutinesApi::class)
class MainViewModelTest {
class MainViewModelTest : BaseViewModelTest<MainViewModel>(){
// Run tasks synchronously
@get:Rule
@@ -31,27 +31,27 @@ class MainViewModelTest {
@get:Rule
var mainCoroutineRule = MainCoroutineRule()
lateinit var viewModel: MainViewModel
override lateinit var viewModel: MainViewModel
@Mock
lateinit var repository: Repository
@Mock
lateinit var helper: CurrencyDataHelper
private val currencyOne = "AUD - Australian Dollar"
private val currencyTwo = "GBP - British Pound"
@Before
fun setUp() {
override fun setUp() {
MockitoAnnotations.initMocks(this)
viewModel = MainViewModel(helper, repository)
viewModel = MainViewModel(repository)
super.setUp()
}
@Test
fun initiate_validBundleValues_successResponse() = runBlocking {
//GIVEN
val currencyOne = "AUD - Australian Dollar"
val currencyTwo = "GBP - British Pound"
val bundle = mock(Bundle()::class.java)
val responseObject = mock(ResponseObject::class.java)
val responseObject = mock(CurrencyModel::class.java)
//WHEN
Mockito.`when`(bundle.getString("parse_1")).thenReturn(currencyOne)
@@ -61,59 +61,50 @@ class MainViewModelTest {
//THEN
viewModel.initiate(bundle)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(true, it.first)
assertNull(it.second)
dataPost.observeOnce {
assertEquals(it, responseObject)
}
}
@Test
fun initiate_invalidBundleValues_successfulResponse() = runBlocking {
//GIVEN
val currencyOne = "corrupted data"
val currencyTwo = "corrupted data again"
val bundle = mock(Bundle()::class.java)
val error = "Corrupted data found"
//WHEN
Mockito.`when`(bundle.getString("parse_1")).thenReturn(currencyOne)
Mockito.`when`(bundle.getString("parse_2")).thenReturn(currencyTwo)
Mockito.`when`(helper.getDataFromApi(currencyOne, currencyTwo))
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.doAnswer { throw IOException(error) }
//THEN
viewModel.initiate(bundle)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(false, it.first)
assertEquals(it.second, error)
errorPost.observeOnce {
assertEquals(error, it)
}
}
@Test
fun initiate_sameBundleValues_successfulResponse() = runBlocking {
//GIVEN
val currencyOne = "AUD - Australian Dollar"
val bundle = mock(Bundle()::class.java)
val responseObject = mock(CurrencyModel::class.java)
//WHEN
Mockito.`when`(bundle.getString("parse_1")).thenReturn(null)
Mockito.`when`(bundle.getString("parse_2")).thenReturn(null)
Mockito.`when`(repository.getConversionPair()).thenReturn(Pair(currencyOne, currencyOne))
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
//THEN
viewModel.initiate(bundle)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(true, it.first)
assertNull(it.second)
dataPost.observeOnce {
assertEquals(responseObject, it)
}
}
@@ -129,12 +120,9 @@ class MainViewModelTest {
//THEN
viewModel.initiate(bundle)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(false, it.first)
assertEquals("Select currencies", it.second)
errorPost.observeOnce {
assertEquals("Select both currencies", it)
}
}
@@ -142,11 +130,9 @@ class MainViewModelTest {
@Test
fun setCurrencyName_validValues_successResponse() = runBlocking {
//GIVEN
val currencyOne = "AUD - Australian Dollar"
val currencyTwo = "GBP - British Pound"
viewModel.rateIdTo = currencyTwo
val tag = "top"
val responseObject = mock(ResponseObject::class.java)
val responseObject = mock(CurrencyModel::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
@@ -154,24 +140,18 @@ class MainViewModelTest {
//THEN
viewModel.setCurrencyName(tag, currencyOne)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(true, it.first)
Log.i("tag", "${it.first} ${it.second}")
assertNull(it.second)
dataPost.observeOnce {
assertEquals(responseObject, it)
}
}
@Test
fun setCurrencyName_sameValues_successfulResponse() = runBlocking {
//GIVEN
val currencyOne = "AUD - Australian Dollar"
val currencyTwo = "GBP - British Pound"
viewModel.rateIdTo = currencyOne
val tag = "top"
val responseObject = mock(ResponseObject::class.java)
val responseObject = mock(CurrencyModel::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
@@ -179,35 +159,27 @@ class MainViewModelTest {
//THEN
viewModel.setCurrencyName(tag, currencyOne)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(true, it.first)
assertNull(it.second)
dataPost.observeOnce {
assertEquals(responseObject, it)
}
}
@Test
fun setCurrencyName_invalidValues_unsuccessfulResponse() = runBlocking {
//GIVEN
val currencyOne = "AUD - Australian Dollar"
val currencyTwo = "GBP - British Pound"
val error = "Data is corrupted"
viewModel.rateIdTo = "corrupted"
val tag = "top"
val responseObject = mock(ResponseObject::class.java)
val responseObject = mock(CurrencyModel::class.java)
//WHEN
Mockito.`when`(repository.getDataFromApi(currencyOne, currencyTwo))
.thenReturn(responseObject)
Mockito.`when`(repository.getDataFromApi(currencyOne, "corrupted"))
.doAnswer { throw IOException(error) }
//THEN
viewModel.setCurrencyName(tag, currencyOne)
viewModel.operationStartedListener.observeOnce {
assertEquals(true, it)
}
viewModel.operationFinishedListener.observeOnce {
assertEquals(false, it.first)
assertNotNull(it.second)
errorPost.observeOnce {
assertEquals(error, it)
}
}

View File

@@ -2,6 +2,7 @@ package com.appttude.h_mal.easycc.ui.widget
import androidx.arch.core.executor.testing.InstantTaskExecutorRule
import com.appttude.h_mal.easycc.data.repository.Repository
import com.appttude.h_mal.easycc.ui.BaseViewModelTest
import com.appttude.h_mal.easycc.utils.observeOnce
import org.junit.Assert.*
import org.junit.Before
@@ -15,21 +16,23 @@ import org.mockito.MockitoAnnotations
private const val currencyOne = "AUD - Australian Dollar"
private const val currencyTwo = "GBP - British Pound"
class WidgetViewModelTest {
class WidgetViewModelTest : BaseViewModelTest<WidgetViewModel>(){
// Run tasks synchronously
@get:Rule
val instantTaskExecutorRule: InstantTaskExecutorRule = InstantTaskExecutorRule()
lateinit var viewModel: WidgetViewModel
override lateinit var viewModel: WidgetViewModel
@Mock
lateinit var repository: Repository
@Before
fun setUp() {
override fun setUp() {
MockitoAnnotations.initMocks(this)
viewModel = WidgetViewModel(repository)
super.setUp()
}
@Test
@@ -75,7 +78,6 @@ class WidgetViewModelTest {
//THEN
val dialogResult = viewModel.getSubmitDialogMessage()
assertEquals(dialogResult, "Create widget for AUDGBP?")
}
@Test
@@ -86,9 +88,9 @@ class WidgetViewModelTest {
//THEN
viewModel.submitSelectionOnClick()
viewModel.operationFinishedListener.observeOnce {
assertEquals(it.first, true)
assertNull(it.second)
dataPost.observeOnce {
assert(it is Unit)
}
}
@@ -100,20 +102,23 @@ class WidgetViewModelTest {
//THEN
viewModel.submitSelectionOnClick()
viewModel.operationFinishedListener.observeOnce {
assertEquals(it.first, false)
assertNotNull(it.second)
errorPost.observeOnce {
assertEquals("Selected rates cannot be the same", it)
}
}
@Test
fun submitSelectionOnClick_noInput_unsuccessfulResponse() {
//GIVEN
viewModel.rateIdFrom = null
viewModel.rateIdTo = null
//THEN
viewModel.submitSelectionOnClick()
viewModel.operationFinishedListener.observeOnce {
assertEquals(it.first, false)
assertNotNull(it.second)
errorPost.observeOnce {
assertEquals("Selections incomplete", it)
}
}
}