Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
13 commits
Select commit Hold shift + click to select a range
c92dccf
#307 - feat : 게시글의 댓글을 조회하는 레포지토리 코드 반환타입을 Result로 변경
hegunhee Jul 25, 2025
1f1d499
#307 - test : 게시글의 댓글을 조회하는 레포지토리 코드 테스트 코드 작성
hegunhee Jul 25, 2025
bcb8fd7
#307 - feat : 정책의 댓글을 가져오는 코드를 flow에서 one-shot방식으로 수정
hegunhee Jul 25, 2025
6edd194
#307 - feat : 게시글의 댓글을 가져오는 코드를 flow에서 Result 타입으로 수정
hegunhee Jul 25, 2025
d24f1d9
#307 - feat : 게시글의 댓글을 가져오는 ViewModel 코드를 flow에서 one-shot 방식으로 변경
hegunhee Jul 25, 2025
20bb828
#307 - feat : 게시글에 댓글을 추가하는 레포지토리 코드 반환 타입을 Result로 변경
hegunhee Jul 25, 2025
90bb433
#307 - feat : 게시글의 댓글을 추가하는 코드를 viewModel에서 Result 타입으로 처리
hegunhee Jul 25, 2025
7b0f9c1
#307 - feat : 데이터가 메시지형태로 들어올경우 반환값으로 담아주기 위해 메시지응답 클래스 작성
hegunhee Jul 25, 2025
cbec3d4
#307 - feat : 게시글에 댓글을 수정하는 레포지토리 코드 반환 타입을 Result로 작성
hegunhee Jul 25, 2025
c628e85
#307 - feat : 게시글에 댓글을 수정하는 뷰모델 코드를 Result타입으로 작성
hegunhee Jul 25, 2025
1c77009
#307 - feat : 댓글 좋아요 레포지토리 코드 반환 타입을 Result로 작성
hegunhee Jul 25, 2025
68a4703
#307 - feat : 댓글 좋아요를 적용하는 뷰모델에서 Result 타입으로 작성
hegunhee Jul 25, 2025
bf31c3f
#307 - style : 생성자 간소화
hegunhee Jul 25, 2025
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
Original file line number Diff line number Diff line change
Expand Up @@ -5,80 +5,36 @@ import com.core.exception.NoDataException
import com.youthtalk.data.CommentService
import com.youthtalk.dto.comment.AddCommentRequest
import com.youthtalk.dto.comment.CommentLikeRequest
import com.youthtalk.dto.comment.CommentResponse
import com.youthtalk.dto.comment.ModifyCommentRequest
import com.youthtalk.mapper.toData
import com.youthtalk.model.comment.CommentInfo
import com.youthtalk.utils.ErrorUtils.throwableError
import com.youthtalk.utils.ErrorUtils.createResult
import javax.inject.Inject
import kotlinx.coroutines.flow.Flow
import kotlinx.coroutines.flow.flow

class CommentRepositoryImpl @Inject constructor(
private val commentService: CommentService
) : CommentRepository {
override fun getPolicyComment(policyId: Long): Flow<CommentInfo> = flow {
runCatching {
commentService.getPolicyComment(policyId)
}
.onSuccess { response ->
emit(response.data?.toData() ?: CommentInfo(0, listOf()))
}
.onFailure {
throwableError<List<CommentResponse>>(it)
}
override suspend fun getPolicyComment(policyId: Long): Result<CommentInfo> = createResult {
commentService.getPolicyComment(policyId).data?.toData() ?: CommentInfo(0, listOf())
}

override fun getPostDetailComments(postId: Long): Flow<CommentInfo> = flow {
runCatching {
commentService.getPostDetailComments(postId)
}
.onSuccess { response ->
emit(response.data?.toData() ?: CommentInfo(0, listOf()))
}
.onFailure {
throwableError<List<CommentResponse>>(it)
}
override suspend fun getPostDetailComments(postId: Long): Result<CommentInfo> = createResult {
commentService.getPostDetailComments(postId).data?.toData() ?: CommentInfo(0, listOf())
}

override fun postPostAddComment(postId: Long, message: String): Flow<Long> = flow {
override suspend fun postPostAddComment(postId: Long, message: String): Result<Long> = createResult {
val requestBody = AddCommentRequest(postId, message).toRequestBody()
runCatching {
commentService.postPostAddComment(requestBody)
}
.onSuccess { response ->
response.data?.let { data ->
emit(data.commentId)
} ?: throw NoDataException()
}
.onFailure {
throwableError<List<CommentResponse>>(it)
}
commentService.postPostAddComment(requestBody).data?.commentId ?: throw NoDataException()
}

override fun patchComment(commentId: Long, message: String): Flow<Long> = flow {
override suspend fun patchComment(commentId: Long, message: String): Result<Long> = createResult {
val requestBody = ModifyCommentRequest(commentId, message).toRequestBody()
runCatching {
commentService.patchComment(requestBody)
}
.onSuccess { _ ->
emit(commentId)
}
.onFailure {
throwableError<List<CommentResponse>>(it)
}
commentService.patchComment(requestBody)
commentId
}

override fun postLikes(commentId: Long, isLike: Boolean): Flow<String> = flow {
override suspend fun postLikes(commentId: Long, isLike: Boolean): Result<String> = createResult {
val requestBody = CommentLikeRequest(commentId, !isLike).toRequestBody()
runCatching {
commentService.postLikes(requestBody)
}
.onSuccess { response ->
emit(response.message)
}
.onFailure {
throwableError<Unit>(it)
}
commentService.postLikes(requestBody).message
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,266 @@
package com.youthtalk.repository

import com.core.exception.BadRequestException
import com.youthtalk.data.CommentService
import com.youthtalk.dto.CommonResponse
import com.youthtalk.dto.PostAddCommentResponse
import com.youthtalk.dto.comment.CommentInfoResponse
import com.youthtalk.dto.comment.CommentResponse
import com.youthtalk.dto.toResponseBody
import com.youthtalk.mapper.toData
import com.youthtalk.model.comment.CommentInfo
import com.youthtalk.repository.model.MessageResponse
import kotlinx.coroutines.runBlocking
import kotlinx.coroutines.test.runTest
import org.junit.Assert.assertEquals
import org.junit.Assert.assertNotNull
import org.junit.Assert.assertThrows
import org.junit.Test
import org.junit.runner.RunWith
import org.mockito.InjectMocks
import org.mockito.Mock
import org.mockito.junit.MockitoJUnitRunner
import org.mockito.kotlin.any
import org.mockito.kotlin.verify
import org.mockito.kotlin.whenever
import retrofit2.HttpException
import retrofit2.Response

@RunWith(MockitoJUnitRunner::class)
class CommentRepositoryTest {

@InjectMocks
private lateinit var sut: CommentRepositoryImpl

@Mock
private lateinit var commentService: CommentService

@Test
fun givenPolicyId_whenGetPolicyComment_thenReturnsComments() {
runTest {
// given
val policyId = 1L
val commentResponse = CommentInfoResponse(1, listOf(CommentResponse(1L, 1L, "asd", "asd", true, null, "2025-05-03 20:31:23")))
val comments = commentResponse.toData()
whenever(commentService.getPolicyComment(policyId)).thenReturn(CommonResponse(200, "요청에 성공하였습니다", "S01", commentResponse))

// when
val result = sut.getPolicyComment(policyId).getOrThrow()

// then
assertEquals(comments, result)
verify(commentService).getPolicyComment(policyId)
}
}

@Test
fun givenPolicyId_whenGetPolicyComment_thenReturnsEmptyComments() {
runTest {
// given
val policyId = 2L
val emptyComment = CommentInfo(0, listOf())
whenever(commentService.getPolicyComment(policyId)).thenReturn(CommonResponse(200, "해당하는 댓글이 없습니다.", "S09", null))

// when
val result = sut.getPolicyComment(policyId).getOrThrow()

// then
assertEquals(emptyComment, result)
verify(commentService).getPolicyComment(policyId)
}
}

@Test
fun givenNotFoundPolicyId_whenGetPolicyComment_thenThrows400Exception() {
runTest {
// given
val policyId = 123L
whenever(commentService.getPolicyComment(policyId)).thenThrow(
HttpException(
Response.error<Any>(
400,
toResponseBody(CommonResponse<Unit?>(400, "해당 정책을 찾을 수 없습니다.", "PC01", null))
)
)
)

// when
assertThrows(BadRequestException::class.java) {
runBlocking {
sut.getPolicyComment(policyId)
.onFailure {
assertEquals("해당 정책을 찾을 수 없습니다.", it.message)
}.getOrThrow()
}
}

// then
verify(commentService).getPolicyComment(policyId)
}
}

@Test
fun givenNotValidPolicyId_whenGetPolicyComment_thenThrows400Exception() {
runTest {
// given
val policyId = 1231321L
whenever(commentService.getPolicyComment(policyId)).thenThrow(
HttpException(
Response.error<Any>(
400,
toResponseBody(CommonResponse<Unit?>(400, "유효하지 않은 값을 입력하였습니다.", "F01", null))
)
)
)

// when
assertThrows(BadRequestException::class.java) {
runBlocking {
sut.getPolicyComment(policyId)
.onFailure {
assertEquals("유효하지 않은 값을 입력하였습니다.", it.message)
}.getOrThrow()
}
}

// then
verify(commentService).getPolicyComment(policyId)
}
}

@Test
fun givenPostId_whenGetPostComment_thenReturnsComments() {
runTest {
// given
val postId = 1L
val commentResponse = CommentInfoResponse(1, listOf(CommentResponse(1L, 1L, "asd", "asd", true, null, "2025-05-03 20:31:23")))
val comments = commentResponse.toData()
whenever(commentService.getPostDetailComments(postId)).thenReturn(CommonResponse(200, "요청에 성공하였습니다", "S01", commentResponse))

// when
val result = sut.getPostDetailComments(postId).getOrThrow()

// then
assertEquals(comments, result)
verify(commentService).getPostDetailComments(postId)
}
}

@Test
fun givenPostId_whenPostComment_thenReturnsCommentId() {
runTest {
// given
val postId = 3L
val commentId = 123L

whenever(
commentService.postPostAddComment(any())
).thenReturn(CommonResponse(200, "댓글을 성공적으로 등록했습니다.", "S06", PostAddCommentResponse(commentId)))

// when
val result = sut.postPostAddComment(postId, "댓글 내용").getOrThrow()

// when
assertEquals(commentId, result)
verify(commentService).postPostAddComment(any())
}
}

@Test
fun givenCommentInfo_whenPatchComment_thenReturnsCommentId() {
runTest {
// given
val commentId = 123L
val message = "hello"

whenever(commentService.patchComment(any())).thenReturn(CommonResponse(200, "댓글을 성공적으로 수정했습니다.", "S07", null))

// when
val result = sut.patchComment(commentId, message).getOrThrow()

// then
assertNotNull(result)
verify(commentService).patchComment(any())
}
}

@Test
fun givenNotValidCommentId_whenPatchComment_thenThrowBadRequestException() {
runTest {
// given
val commentId = 123123L
val message = "asjdalsjd"

whenever(commentService.patchComment(any())).thenThrow(
HttpException(
Response.error<Any>(
400,
toResponseBody(CommonResponse(400, "유효하지 않은 값을 입력하였습니다.", "F01", MessageResponse(listOf("must not be null"))))
)
)
)

// when
assertThrows(BadRequestException::class.java) {
runBlocking {
sut.patchComment(commentId, message)
.onFailure {
assertEquals("유효하지 않은 값을 입력하였습니다.", it.message)
}.getOrThrow()
}
}

// then
verify(commentService).patchComment(any())
}
}

@Test
fun givenPostLike_whenPostLike_thenWorksFine() {
runTest {
// given
val commentId = 133L
val isSetLiked = true

whenever(commentService.postLikes(any())).thenReturn(CommonResponse(200, "좋아요 등록이 완료되었습니다.", "S10", null))

// when
val result = sut.postLikes(commentId, isSetLiked).getOrThrow()

// then
assertEquals("좋아요 등록이 완료되었습니다.", result)
verify(commentService).postLikes(any())
}
}

@Test
fun givenNotFoundPostId_whenPostLike_thenThrowsBadRequestException() {
runTest {
// given
val commentId = 12312312L
val isSetLiked = true

whenever(commentService.postLikes(any())).thenThrow(
HttpException(
Response.error<Any>(
400,
toResponseBody(CommonResponse<Unit?>(400, "해당 댓글을 찾을 수 없습니다.", "C01", null))
)
)
)

// when
assertThrows(BadRequestException::class.java) {
runBlocking {
sut.postLikes(commentId, isSetLiked)
.onFailure {
assertEquals("해당 댓글을 찾을 수 없습니다.", it.message)
}.getOrThrow()
}
}

// then
verify(commentService).postLikes(any())
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
package com.youthtalk.repository.model

import kotlinx.serialization.Serializable

@Serializable
data class MessageResponse(val message: List<String>)
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
package com.core.dataapi.repository

import com.youthtalk.model.comment.CommentInfo
import kotlinx.coroutines.flow.Flow

interface CommentRepository {
fun getPolicyComment(policyId: Long): Flow<CommentInfo>
fun getPostDetailComments(postId: Long): Flow<CommentInfo>
fun postPostAddComment(postId: Long, message: String): Flow<Long>
fun patchComment(commentId: Long, message: String): Flow<Long>
fun postLikes(commentId: Long, isLike: Boolean): Flow<String>
suspend fun getPolicyComment(policyId: Long): Result<CommentInfo>
suspend fun getPostDetailComments(postId: Long): Result<CommentInfo>
suspend fun postPostAddComment(postId: Long, message: String): Result<Long>
suspend fun patchComment(commentId: Long, message: String): Result<Long>
suspend fun postLikes(commentId: Long, isLike: Boolean): Result<String>
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import javax.inject.Inject
class PatchCommentUseCase @Inject constructor(
private val commentRepository: CommentRepository
) {
operator fun invoke(commentId: Long, message: String) = commentRepository.patchComment(commentId, message)
suspend operator fun invoke(commentId: Long, message: String) = commentRepository.patchComment(commentId, message)
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,5 @@ import javax.inject.Inject
class PostAddPostCommentUseCase @Inject constructor(
private val commentRepository: CommentRepository
) {
operator fun invoke(postId: Long, message: String) = commentRepository.postPostAddComment(postId, message)
suspend operator fun invoke(postId: Long, message: String) = commentRepository.postPostAddComment(postId, message)
}
Loading