Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Test: reaction unit test #123

Merged
merged 2 commits into from
Dec 9, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 22 additions & 0 deletions android/app/src/main/java/com/goliath/emojihub/models/Reaction.kt
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,26 @@ class ReactionWithEmoji(
val emojiId: String = dto.emojiId
val postId: String = dto.postId
val emojiDto: EmojiDto? = dto.emojiDto

override fun equals(other: Any?): Boolean {
if (other == null || other !is ReactionWithEmoji) {
return false
}
return this.id == other.id &&
this.createdAt == other.createdAt &&
this.createdBy == other.createdBy &&
this.emojiId == other.emojiId &&
this.postId == other.postId &&
this.emojiDto == other.emojiDto
}

override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + createdAt.hashCode()
result = 31 * result + createdBy.hashCode()
result = 31 * result + emojiId.hashCode()
result = 31 * result + postId.hashCode()
result = 31 * result + (emojiDto?.hashCode() ?: 0)
return result
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ interface ReactionRepository {
suspend fun fetchReactionList(postId: String, emojiUnicode: String): Flow<PagingData<ReactionWithEmojiDto>>
suspend fun uploadReaction(postId: String, emojiId: String): Response<Unit>
suspend fun getReactionWithId(id: String)
suspend fun deleteReaction(reactionId: String)
suspend fun deleteReaction(reactionId: String): Response<Unit>
}

@Singleton
Expand All @@ -37,7 +37,7 @@ class ReactionRepositoryImpl @Inject constructor(
TODO()
}

override suspend fun deleteReaction(reactionId: String) {
reactionApi.deleteReaction(reactionId)
override suspend fun deleteReaction(reactionId: String): Response<Unit> {
return reactionApi.deleteReaction(reactionId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ interface ReactionUseCase {

@Singleton
class ReactionUseCaseImpl @Inject constructor(
private val repository: ReactionRepository,
private val reactionRepository: ReactionRepository,
private val errorController: ApiErrorController
): ReactionUseCase {

Expand All @@ -37,11 +37,11 @@ class ReactionUseCaseImpl @Inject constructor(
}

override suspend fun fetchReactionList(postId: String, emojiUnicode: String): Flow<PagingData<ReactionWithEmoji>> {
return repository.fetchReactionList(postId, emojiUnicode).map { it.map { dto -> ReactionWithEmoji(dto) } }
return reactionRepository.fetchReactionList(postId, emojiUnicode).map { it.map { dto -> ReactionWithEmoji(dto) } }
}

override suspend fun uploadReaction(postId: String, emojiId: String): Boolean {
val response = repository.uploadReaction(postId, emojiId)
val response = reactionRepository.uploadReaction(postId, emojiId)
return if (response.isSuccessful) {
true
} else {
Expand All @@ -51,10 +51,10 @@ class ReactionUseCaseImpl @Inject constructor(
}

override suspend fun getReactionWithId(id: String) {
repository.getReactionWithId(id)
reactionRepository.getReactionWithId(id)
}

override suspend fun deleteReaction(reactionId: String) {
repository.deleteReaction(reactionId)
reactionRepository.deleteReaction(reactionId)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ class ReactionViewModel @Inject constructor(

val reactionList = reactionUseCase.reactionList

suspend fun fetchReactionList(postId: String, emojiUnicode: String) {
fun fetchReactionList(postId: String, emojiUnicode: String) {
viewModelScope.launch {
reactionUseCase.fetchReactionList(postId, emojiUnicode)
.cachedIn(viewModelScope)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,8 @@ import com.goliath.emojihub.data_sources.CustomError
import com.goliath.emojihub.data_sources.api.EmojiApi
import com.goliath.emojihub.data_sources.remote.EmojiDataSource
import com.goliath.emojihub.mockLogClass
import com.goliath.emojihub.models.EmojiDto
import com.goliath.emojihub.models.UploadEmojiDto
import com.goliath.emojihub.sampleEmojiDto
import retrofit2.Response
import io.mockk.coEvery
import io.mockk.coVerify
Expand All @@ -31,16 +31,6 @@ class EmojiRepositoryImplTest {
private val emojiApi = mockk<EmojiApi>()
private val emojiDataSource = mockk<EmojiDataSource>()
private val emojiRepositoryImpl = EmojiRepositoryImpl(emojiApi, emojiDataSource)
private val sampleEmojiDto = EmojiDto(
createdBy = "channn",
createdAt = "2023-11-24 14:25:05",
savedCount = 1600,
videoLink = "https://storage.googleapis.com/emojihub-e2023.appspot.com/uu_2023-11-24%2014%3A25%3A05.mp4?GoogleAccessId=firebase-adminsdk-zynbm@emojihub-e2023.iam.gserviceaccount.com&Expires=1709443506&Signature=I%2BNRJSZ7nYtmrWs%2Fjv4uVAeW8%2BfHGF6GeV0pZRE4Sp5gCFuXLXBTKpgRBl1j2F%2BSSUStSqvBlktHZofZznGHWtsMYHQ99%2Bv7wcenqZweSWSmzse4s9sKAOkykn7pB9EMnFgax4VqGK4U5ey5HNSCKsjyNa5ZqDH8%2BqF%2FcIjQ3huChDMB2Xw1InaHUve0syvW6uz%2BeooDLo2nkGxdtElsDtomq2cAUMgk7nRNIYciYLGJ%2FsrscW7%2FXfD3rn%2BH3EM9z5S9DHKHWiEmh1xf0wpTtDsXom7p14XnZunnnOxpNO5OMFJi2x1kxZBFVc7U88V19eTmasWxdGV5TZipfN2ZMA%3D%3D",
thumbnailLink = "https://storage.googleapis.com/emojihub-e2023.appspot.com/uu_2023-11-24%2014%3A25%3A05.jpeg?GoogleAccessId=firebase-adminsdk-zynbm@emojihub-e2023.iam.gserviceaccount.com&Expires=1709443506&Signature=lZK4otdQOXBVKz3EeOEgpSqAH5QE3U6KuTz8bo5RwYQ463i0cBEx44zVPJO3dIP%2B3%2FdKkBbJy%2BzIBogKAKUl5jLyP9FwInOZChspQOuI8zp%2FKivvEZImPnoG2C1UiiwB03tHYq0tWEhgj76BB4SarWRtZY4xRZhuVvuJg9%2FNV%2B5XZ7%2BGGjLbzfjc5rA45iwWQGPfgQN0%2FKJsdTieNb5%2F6%2B5QHW4pq7QLxYAGqvea5X6VY1JcUjXU0iZ%2FfI16L%2F1cFZAMPDPNPxC2bbllFH6vkOdb3qKuvGm0M3Y99GCLTv%2BAiObbBCs13AgmBO1OngrBV4db4zNnjUZOtB0rPRgyFw%3D%3D",
id = "0ZF0MFHOV7974YTV3SBN",
label = "love it",
unicode = "U+2764 U+FE0F"
)
@Before
fun setUp() {
mockLogClass()
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
package com.goliath.emojihub.repositories.remote

import androidx.paging.testing.asSnapshot
import com.goliath.emojihub.data_sources.api.ReactionApi
import com.goliath.emojihub.mockLogClass
import com.goliath.emojihub.sampleReactionWithEmojiDto
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import kotlinx.coroutines.runBlocking
import org.junit.Assert.*
import org.junit.Before

import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import retrofit2.Response

@RunWith(JUnit4::class)
class ReactionRepositoryImplTest {
private val reactionApi = mockk<ReactionApi>()
private val reactionRepository = ReactionRepositoryImpl(reactionApi)
@Before
fun setUp() {
mockLogClass()
}

@Test
fun fetchReactionList_returnsFlowOfPagingDataOfReactionWithEmojiDto() {
val numSampleReactions = 10
val sampleReactionWithEmojiDtoList = List(numSampleReactions) { sampleReactionWithEmojiDto }
val expectedFetchedReactionWithEmojiDtoList = List(numSampleReactions*2) { sampleReactionWithEmojiDto }
// *2 because of .asSnapshot() load one more time
coEvery {
reactionApi.fetchReactionList(any(), any(), any(), any())
} returns Response.success(sampleReactionWithEmojiDtoList)
// when
val fetchedReactionPagingDataFlow = runBlocking {
reactionRepository.fetchReactionList("1234", "U+1F44D")
}
val fetchedReactionWithEmojiDtoList = runBlocking {
fetchedReactionPagingDataFlow.asSnapshot()
}
// then
coVerify(exactly = 2) { reactionApi.fetchReactionList(any(), any(), any(), any()) }
runBlocking {
assertEquals(expectedFetchedReactionWithEmojiDtoList.size, fetchedReactionWithEmojiDtoList.size)
assertEquals(expectedFetchedReactionWithEmojiDtoList, fetchedReactionWithEmojiDtoList)
}
}

@Test
fun uploadReaction_success_returnsSuccessResponse() {
// given
val expectedResponse = Response.success(Unit)
coEvery {
reactionApi.uploadReaction(any(), any())
} returns expectedResponse
// when
val response = runBlocking {
reactionRepository.uploadReaction("1234", "1234")
}
// then
coVerify(exactly = 1) { reactionApi.uploadReaction(any(), any()) }
assertEquals(expectedResponse, response)
}

@Test
fun uploadReaction_failure_returnsFailureResponse() {
// given
val expectedResponse = Response.error<Unit>(400, mockk(relaxed = true))
coEvery {
reactionApi.uploadReaction(any(), any())
} returns expectedResponse
// when
val response = runBlocking {
reactionRepository.uploadReaction("1234", "1234")
}
// then
coVerify(exactly = 1) { reactionApi.uploadReaction(any(), any()) }
assertFalse(response.isSuccessful)
}

// @Test
// TODO: Not implemented yet
fun getReactionWithId() {
}

@Test
fun deleteReaction_success_returnsSuccessResponse() {
// given
val expectedResponse = Response.success(Unit)
coEvery {
reactionApi.deleteReaction(any())
} returns expectedResponse
// when
val response = runBlocking {
reactionRepository.deleteReaction("1234")
}
// then
coVerify(exactly = 1) { reactionApi.deleteReaction(any()) }
assertEquals(expectedResponse, response)
}

@Test
fun deleteReaction_failure_returnsFailureResponse() {
// given
val expectedResponse = Response.error<Unit>(400, mockk(relaxed = true))
coEvery {
reactionApi.deleteReaction(any())
} returns expectedResponse
// when
val response = runBlocking {
reactionRepository.deleteReaction("1234")
}
// then
coVerify(exactly = 1) { reactionApi.deleteReaction(any()) }
assertFalse(response.isSuccessful)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,103 @@
package com.goliath.emojihub.usecases

import androidx.paging.PagingData
import androidx.paging.map
import androidx.paging.testing.asSnapshot
import com.goliath.emojihub.createReactionWithEmojiDtoList
import com.goliath.emojihub.data_sources.ApiErrorController
import com.goliath.emojihub.mockLogClass
import com.goliath.emojihub.models.ReactionWithEmoji
import com.goliath.emojihub.repositories.remote.ReactionRepository
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import io.mockk.spyk
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import org.junit.Assert.*
import org.junit.Before

import org.junit.Test
import org.junit.runner.RunWith
import org.junit.runners.JUnit4
import retrofit2.Response

@RunWith(JUnit4::class)
class ReactionUseCaseImplTest {
private val reactionRepository = mockk<ReactionRepository>()
private val apiErrorController = spyk<ApiErrorController>()
private val reactionUseCase = ReactionUseCaseImpl(reactionRepository, apiErrorController)
@Before
fun setUp() {
mockLogClass()
}

@Test
fun updateReactionList_withSamplePagingReactionData_updatesReactionListStateFlow() {
// given
val samplePagingReactionData = mockk<PagingData<ReactionWithEmoji>>()
// when
runBlocking { reactionUseCase.updateReactionList(samplePagingReactionData) }
// then
assertEquals(samplePagingReactionData, reactionUseCase.reactionList.value)
}

@Test
fun fetchReactionList_returnsFlowOfReactionPagingData() {
// given
val sampleReactionPagingDataFlow = createReactionWithEmojiDtoList(5)
val sampleAnswer = sampleReactionPagingDataFlow.map { it.map { dto -> ReactionWithEmoji(dto) } }
coEvery {
reactionRepository.fetchReactionList(any(), any())
} returns sampleReactionPagingDataFlow
// when
val result = runBlocking { reactionUseCase.fetchReactionList("1234", "U+1F44D") }
// then
coVerify(exactly = 1) { reactionRepository.fetchReactionList(any(), any()) }
runBlocking {
val sampleAnswerAsSnapshot = sampleAnswer.asSnapshot()
val resultAsSnapshot = result.asSnapshot()
for (i in sampleAnswerAsSnapshot.indices) {
assertEquals(sampleAnswerAsSnapshot[i], resultAsSnapshot[i])
}
}
}

@Test
fun uploadReaction_successWithValidPostId_returnsTrue() {
// given
val samplePostId = "1234"
val sampleEmojiId = "5678"
coEvery {
reactionRepository.uploadReaction(any(), any())
} returns Response.success(Unit)
// when
val result = runBlocking { reactionUseCase.uploadReaction(samplePostId, sampleEmojiId) }
// then
assertTrue(result)
}

@Test
fun uploadReaction_failureWithInvalidPostId_returnsFalse() {
// given
val samplePostId = "-1234"
val sampleEmojiId = "5678"
coEvery {
reactionRepository.uploadReaction(any(), any())
} returns Response.error(404, mockk(relaxed = true))
// when
val result = runBlocking { reactionUseCase.uploadReaction(samplePostId, sampleEmojiId) }
// then
assertFalse(result)
}

// @Test
// TODO: Not implemented yet
fun getReactionWithId() {
}

// @Test
// TODO: Not implemented yet
fun deleteReaction() {
}
}
Loading