I am trying to unit test my repository . In that i want to write test for function which makes api calls.(function name :- searchImage) The function calls datasource for actual api calls. I am using a fake data source which extends from the shopping data source interface. How can i provide different responses from fake data source for the api calls like no internet , Null body or Success response.
ShoppingRepositoryInterface
interface ShoppingRepository {
suspend fun insertShoppingItem(shoppingItem: ShoppingItem)
suspend fun deleteShoppingItem(shoppingItem: ShoppingItem)
fun getAllShoppingItems() : LiveData<List<ShoppingItem>>
fun getTotalPrice() : LiveData<Float>
suspend fun searchImage(q:String) : Resource<ImageResponse>
}
ShoppingRepositoryImpl
@ViewModelScoped
class ShoppingRepositoryImpl @Inject constructor(
private val dataSource: ShoppingDataSource
) : ShoppingRepository{
override suspend fun insertShoppingItem(shoppingItem: ShoppingItem) = dataSource.insertShoppingItem(shoppingItem)
override suspend fun deleteShoppingItem(shoppingItem: ShoppingItem) = dataSource.deleteShoppingItem(shoppingItem)
override fun getAllShoppingItems() = dataSource.getAllShoppingItems()
override fun getTotalPrice() = dataSource.getTotalPrice()
override suspend fun searchImage(q: String) : Resource<ImageResponse> {
return try {
val response = dataSource.searchImage(q)
if(response.isSuccessful){
response.body()?.let {
Resource.Success(it)
}?:Resource.Error("Some Error Occurred")
}else{
Resource.Error("Some Error Occurred")
}
}catch (e:Exception){
Resource.Error("Couldn't connect to the server.Please try later")
}
}
}
ShoppingReposositoryTest
class ShoppingRepositoryTest{
@get:Rule
val instantTaskExecutorRule = InstantTaskExecutorRule()
private lateinit var repository: ShoppingRepository
private lateinit var dataSource: ShoppingDataSource
private val shoppingItem1 = ShoppingItem("name1",1,price=1f,"url1",1)
private val shoppingItem2 = ShoppingItem("name2",2,price=2f,"url2",2)
private val shoppingItem3 = ShoppingItem("name3",3,price=3f,"url3",3)
@Before
fun setup(){
dataSource = FakeDataSource(mutableListOf(
shoppingItem1
))
repository = ShoppingRepositoryImpl(dataSource)
}
@Test
@ExperimentalCoroutinesApi
fun insertShoppingItem_returnsWhetherItemInserted() = runTest{
//Given
//When
repository.insertShoppingItem(shoppingItem2)
val shoppingList = repository.getAllShoppingItems().getOrAwaitValue()
//Then
assertThat(shoppingList).contains(shoppingItem1)
}
@Test
@ExperimentalCoroutinesApi
fun deleteShoppingItem_returnsWhetherItemDeleted() = runTest{
//Given
//When
repository.deleteShoppingItem(shoppingItem1)
val shoppingList = repository.getAllShoppingItems().getOrAwaitValue()
//Then
assertThat(shoppingList.contains(shoppingItem1)).isFalse()
}
@Test
@ExperimentalCoroutinesApi
fun observeTotalPrice_returnsTotalPrice() = runTest {
//Given
//When
repository.insertShoppingItem(shoppingItem2)
repository.insertShoppingItem(shoppingItem3)
val actual = repository.getTotalPrice().getOrAwaitValue()
val expected = 14f
//Then
assertThat(expected).isEqualTo(actual)
}
@Test
@ExperimentalCoroutinesApi
fun observesSearchImage_returnsNoInternetError() = runTest {
//Given
//When
}
ShoppingDataSourceInterface
interface ShoppingDataSource {
suspend fun insertShoppingItem(shoppingItem:ShoppingItem)
suspend fun deleteShoppingItem(shoppingItem: ShoppingItem)
fun getAllShoppingItems() : LiveData<List<ShoppingItem>>
fun getTotalPrice() : LiveData<Float>
suspend fun searchImage(q:String) : Response<ImageResponse>
}
FakeDataDource
class FakeDataSource(private val list: MutableList<ShoppingItem> = mutableListOf()) : ShoppingDataSource {
private val shoppingList = MutableLiveData<List<ShoppingItem>>()
get() {
field.value=list
return field
}
private val totalPrice = MutableLiveData<Float>()
get(){
var value=0f
for(item in shoppingList.value!!){
value+=(item.price*item.amount)
}
field.value=value
return field
}
override suspend fun insertShoppingItem(shoppingItem: ShoppingItem) {
list.add(shoppingItem)
}
override suspend fun deleteShoppingItem(shoppingItem: ShoppingItem) {
list.remove(shoppingItem)
}
override fun getAllShoppingItems(): LiveData<List<ShoppingItem>> = shoppingList
override fun getTotalPrice(): LiveData<Float> {
return totalPrice
}
override suspend fun searchImage(q: String): Response<ImageResponse> {
TODO("")
}
I cannot use some booleans etc since it extends ShoppingDataSource Interface . I tried mocking as well but that didn't work . What should be done now?