Skip to content

Commit

Permalink
Merge pull request #83 from snuhcs-course/test/android-post
Browse files Browse the repository at this point in the history
Test/android post
  • Loading branch information
thisisWooyeol authored Nov 30, 2023
2 parents 28450e6 + 3c2eba8 commit db073a0
Show file tree
Hide file tree
Showing 7 changed files with 252 additions and 31 deletions.
25 changes: 25 additions & 0 deletions android/app/src/main/java/com/goliath/emojihub/models/Post.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,31 @@ class Post(
val createdBy: String = dto.createdBy
val content: String = dto.content
val reaction: List<String> = dto.reaction

override fun equals(other: Any?): Boolean {
if (this === other) return true
if (javaClass != other?.javaClass) return false

other as Post
if (id != other.id) return false
if (createdAt != other.createdAt) return false
if (modifiedAt != other.modifiedAt) return false
if (createdBy != other.createdBy) return false
if (content != other.content) return false
if (reaction != other.reaction) return false

return true
}

override fun hashCode(): Int {
var result = id.hashCode()
result = 31 * result + createdAt.hashCode()
result = 31 * result + modifiedAt.hashCode()
result = 31 * result + createdBy.hashCode()
result = 31 * result + content.hashCode()
result = 31 * result + reaction.hashCode()
return result
}
}

data class PostDto(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,9 @@ import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.StateFlow
import kotlinx.coroutines.flow.map
import javax.inject.Inject
import javax.inject.Singleton

sealed interface PostUseCase {
interface PostUseCase {
val postList: StateFlow<PagingData<Post>>
val myPostList: StateFlow<PagingData<Post>>
suspend fun updatePostList(data: PagingData<Post>)
Expand All @@ -26,6 +27,7 @@ sealed interface PostUseCase {
suspend fun deletePost(id: String)
}

@Singleton
class PostUseCaseImpl @Inject constructor(
private val repository: PostRepository,
private val errorController: ApiErrorController
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ import kotlinx.coroutines.flow.update
import javax.inject.Inject
import javax.inject.Singleton

sealed interface UserUseCase {
interface UserUseCase {
val userState: StateFlow<User?>

suspend fun fetchUserList()
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ package com.goliath.emojihub.repositories.remote
import androidx.paging.testing.asSnapshot
import com.goliath.emojihub.data_sources.api.PostApi
import com.goliath.emojihub.mockLogClass
import com.goliath.emojihub.models.PostDto
import com.goliath.emojihub.models.UploadPostDto
import com.goliath.emojihub.samplePostDto
import io.mockk.coEvery
import io.mockk.coVerify
import retrofit2.Response
Expand All @@ -20,16 +20,6 @@ import org.junit.runners.JUnit4
class PostRepositoryImplTest {
private val postApi = mockk<PostApi>()
private val postRepositoryImpl = PostRepositoryImpl(postApi)
private val samplePostDto = PostDto(
id = "1234",
createdAt = "2023.09.16",
createdBy = "channn",
content = "조금 전에 앞에 계신 분이 실수로 지갑을 흘리셨다. " +
"지갑이 하수구 구멍으로 빠지려는 찰나, 발로 굴러가는 지갑을 막아서 다행히 참사는 막을 수 있었다. " +
"지갑 주인분께서 감사하다고 카페 드림에서 커피도 한 잔 사주셨다.",
modifiedAt = "2023.10.23",
reaction = listOf("good", "check", "good")
)
@Before
fun setUp() {
mockLogClass()
Expand All @@ -56,6 +46,27 @@ class PostRepositoryImplTest {
}
}

@Test
fun fetchMyPostList_returnsFlowOfPagingDataOfPostDto() {
// given
val numSamplePosts = 10
val samplePostDtoList = List(numSamplePosts) { samplePostDto }
val expectedFetchedPostDtoList = List(numSamplePosts*2) { samplePostDto }
// *2 because of .asSnapshot() load one more time
coEvery {
postApi.fetchMyPostList(any())
} returns Response.success(samplePostDtoList)
// when
val fetchedPostPagingDataFlow = runBlocking { postRepositoryImpl.fetchMyPostList() }
val fetchedPostDtoList = runBlocking { fetchedPostPagingDataFlow.asSnapshot() }
// then
coVerify(exactly = 2) { postApi.fetchMyPostList(any()) }
runBlocking {
assertEquals(expectedFetchedPostDtoList.size, fetchedPostDtoList.size)
assertEquals(expectedFetchedPostDtoList, fetchedPostDtoList)
}
}

@Test
fun uploadPost_returnsSuccessResponse() {
// given
Expand Down Expand Up @@ -118,7 +129,7 @@ class PostRepositoryImplTest {
postApi.editPost(any(), any())
} returns Response.success(Unit)
// when
val response = runBlocking {
runBlocking {
postRepositoryImpl.editPost(samplePostDto.id, samplePostDto.content)
}
// then
Expand All @@ -137,7 +148,7 @@ class PostRepositoryImplTest {
postApi.deletePost(any())
} returns Response.success(Unit)
// when
val response = runBlocking { postRepositoryImpl.deletePost(samplePostDto.id) }
runBlocking { postRepositoryImpl.deletePost(samplePostDto.id) }
// then
coVerify(exactly = 1) { postApi.deletePost(samplePostDto.id) }
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,17 +3,17 @@ package com.goliath.emojihub.usecases
import androidx.paging.PagingData
import androidx.paging.map
import androidx.paging.testing.asSnapshot
import com.goliath.emojihub.createDeterministicDummyPostDtoList
import com.goliath.emojihub.data_sources.ApiErrorController
import com.goliath.emojihub.models.Post
import com.goliath.emojihub.models.PostDto
import com.goliath.emojihub.models.UploadPostDto
import com.goliath.emojihub.repositories.remote.PostRepository
import com.goliath.emojihub.samplePostDto
import io.mockk.coEvery
import io.mockk.coVerify
import io.mockk.mockk
import io.mockk.spyk
import io.mockk.verify
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.map
import kotlinx.coroutines.runBlocking
import org.junit.Assert.*
Expand All @@ -39,10 +39,20 @@ class PostUseCaseImplTest {
assertEquals(samplePagingPostData, postUseCaseImpl.postList.value)
}

@Test
fun updateMyPostList_withSamplePagingPostData_updatesMyPostListStateFlow() {
// given
val samplePagingPostData = mockk<PagingData<Post>>()
// when
runBlocking { postUseCaseImpl.updateMyPostList(samplePagingPostData) }
// then
assertEquals(samplePagingPostData, postUseCaseImpl.myPostList.value)
}

@Test
fun fetchPostList_returnsFlowOfPostPagingData() {
// given
val samplePostPagingDataFlow = spyk<Flow<PagingData<PostDto>>>()
val samplePostPagingDataFlow = createDeterministicDummyPostDtoList(5)
val sampleAnswer = samplePostPagingDataFlow.map { it.map { dto -> Post(dto) } }
coEvery {
postRepository.fetchPostList()
Expand All @@ -52,10 +62,38 @@ class PostUseCaseImplTest {
// then
coVerify(exactly = 1) { postRepository.fetchPostList() }
runBlocking {
assertEquals(
sampleAnswer.asSnapshot(),
fetchedPostPagingDataFlow.asSnapshot()
)
val sampleAnswerAsSnapshot = sampleAnswer.asSnapshot()
val fetchedPostPagingDataFlowAsSnapshot = fetchedPostPagingDataFlow.asSnapshot()
for (i in sampleAnswerAsSnapshot.indices) {
assertEquals(
sampleAnswerAsSnapshot[i],
fetchedPostPagingDataFlowAsSnapshot[i]
)
}
}
}

@Test
fun fetchMyPostList_returnsFlowOfPostPagingData() {
// given
val samplePostPagingDataFlow = createDeterministicDummyPostDtoList(5)
val sampleAnswer = samplePostPagingDataFlow.map { it.map { dto -> Post(dto) } }
coEvery {
postRepository.fetchMyPostList()
} returns samplePostPagingDataFlow
// when
val fetchedPostPagingDataFlow = runBlocking { postUseCaseImpl.fetchMyPostList() }
// then
coVerify(exactly = 1) { postRepository.fetchMyPostList() }
runBlocking {
val sampleAnswerAsSnapshot = sampleAnswer.asSnapshot()
val fetchedPostPagingDataFlowAsSnapshot = fetchedPostPagingDataFlow.asSnapshot()
for (i in sampleAnswerAsSnapshot.indices) {
assertEquals(
sampleAnswerAsSnapshot[i],
fetchedPostPagingDataFlowAsSnapshot[i]
)
}
}
}

Expand Down Expand Up @@ -93,14 +131,6 @@ class PostUseCaseImplTest {
fun getPostWithId_success_returnsPostDto() {
// given
val sampleId = "sampleId"
val samplePostDto = PostDto(
sampleId,
"sampleCreatedAt",
"sampleUpdatedAt",
"sampleUserId",
"sampleUserAvatarUrl",
listOf("sampleReaction1", "sampleReaction2"),
)
coEvery {
postRepository.getPostWithId(any())
} returns samplePostDto
Expand Down
37 changes: 36 additions & 1 deletion android/app/src/test/java/com/goliath/emojihub/utils.kt
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,8 @@ import androidx.paging.PagingData
import androidx.paging.map
import com.goliath.emojihub.models.Emoji
import com.goliath.emojihub.models.EmojiDto
import com.goliath.emojihub.models.Post
import com.goliath.emojihub.models.PostDto
import io.mockk.every
import io.mockk.mockkStatic
import kotlinx.coroutines.flow.Flow
Expand All @@ -19,6 +21,7 @@ fun mockLogClass() {
every { Log.e(any(), any()) } returns 0
}

// EMOJI TESTING UTILS
val dummyUsernames = listOf("channn", "doggydog", "meow_0w0", "mpunchmm", "kick_back")
val dummyUnicodes = listOf("U+1F44D", "U+1F600", "U+1F970", "U+1F60E", "U+1F621", "U+1F63A", "U+1F496", "U+1F415")
const val dummyMaxSavedCounts = 2000
Expand All @@ -40,7 +43,39 @@ fun createDeterministicDummyEmojiDtoList(listSize : Int): Flow<PagingData<EmojiD
}
return flowOf(PagingData.from(dummyEmojiList))
}

fun createDeterministicDummyEmojiList(listSize: Int): Flow<PagingData<Emoji>> {
return createDeterministicDummyEmojiDtoList(listSize).map { it.map { dto -> Emoji(dto) } }
}

// POST TESTING UTILS
val samplePostDto = PostDto(
id = "1234",
createdAt = "2023.09.16",
createdBy = "channn",
content = "조금 전에 앞에 계신 분이 실수로 지갑을 흘리셨다. " +
"지갑이 하수구 구멍으로 빠지려는 찰나, 발로 굴러가는 지갑을 막아서 다행히 참사는 막을 수 있었다. " +
"지갑 주인분께서 감사하다고 카페 드림에서 커피도 한 잔 사주셨다.",
modifiedAt = "2023.10.23",
reaction = listOf("good", "check", "good")
)
fun createDeterministicDummyPostDtoList(listSize : Int): Flow<PagingData<PostDto>> {
val dummyPostList = mutableListOf<PostDto>()
for (i in 0 until listSize) {
dummyPostList.add(
PostDto(
id = "1234",
createdAt = "2023.09.16",
createdBy = "channn",
content = "조금 전에 앞에 계신 분이 실수로 지갑을 흘리셨다. " +
"지갑이 하수구 구멍으로 빠지려는 찰나, 발로 굴러가는 지갑을 막아서 다행히 참사는 막을 수 있었다. " +
"지갑 주인분께서 감사하다고 카페 드림에서 커피도 한 잔 사주셨다.",
modifiedAt = "2023.10.23",
reaction = listOf("good", "check", "good")
)
)
}
return flowOf(PagingData.from(dummyPostList))
}
fun createDeterministicDummyPostList(listSize: Int): Flow<PagingData<Post>> {
return createDeterministicDummyPostDtoList(listSize).map { it.map { dto -> Post(dto) } }
}
Loading

0 comments on commit db073a0

Please sign in to comment.