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

feat: 도서관 남은 좌석 API 구현 #387

Open
wants to merge 18 commits into
base: develop
Choose a base branch
from

Conversation

boiledEgg-s
Copy link
Collaborator

@boiledEgg-s boiledEgg-s commented Nov 19, 2024

https://kuring.atlassian.net/browse/KURING-224?atlOrigin=eyJpIjoiNWVhZjQ3N2Y3YWVmNGMyZTg2Mjk0MTY0M2M5NDc3OGEiLCJwIjoiaiJ9

요약

  • 도서관 남은 좌석을 가져오는 API을 프로젝트에서 사용하기 위해 Service, Client, Repository를 구현했습니다.
  • 화면에서 테스트 해보기 어려워 테스트 코드도 구현했습니다! 근데 테스트 코드도 "300줄 미만 PR" 컨벤션에 포함이 되는건가요?
  • Response를 다 쪼개서 구현을 해놨는데 이름 지어주는게 너무 어렵네요..

추가 수정 사항

  • 리뷰 사항을 반영해봤습니다!
  • 추후 도메인 및 dto 수정을 대비한 trailing comma 반영
  • 난독화 문제에 대비한 @SerializedName 추가
  • runCatching을 사용한 예외처리
  • 예외처리 변경으로 인한 테스트 코드 수정

@boiledEgg-s boiledEgg-s self-assigned this Nov 19, 2024
Copy link
Member

@mwy3055 mwy3055 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Retrofit response 클래스를 proguard-rules.pro의 30라인 밑에 하나도 빠짐없이 선언해 주세요. 난독화 때문에 release에서 제대로 파싱하지 못하는 경우가 많았습니다.

그 외에는 코멘트 가볍게 읽어보시면 되겠습니다.

Comment on lines +3 to +7
plugins {
kuring("feature")
kuringPrimitive("retrofit")
kuringPrimitive("test")
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 이해하기 어렵지 않았나요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 아직 제대로 이해하진 못했어요,,
저 플러그인들에 필요한 라이브러리들이 있겠거니 해서 일단 넣었습니다😅

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋ이것도 강의 해줄게요

Comment on lines 12 to 18
override suspend fun getRemainingSeats(): List<LibraryRoom> {
return try {
libraryClient.fetchRoomSeatStatus().toLibraryAreaList()
} catch (e: HttpException) {
emptyList()
}
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예외처리 굿

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그런데 여기서 예외처리하는게 맞을까요? UI쪽에서 에러 캐치를 해야 특정 Exception에 대응하는 화면을 만들 수 있는 등의 처리를 할 수 있을 것 같아서요.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

음.. 생각해 보니 그렇네요. 여기서는 exception을 그대로 던지거나, exception을 잡고 LibraryException 같은 커스텀 예외를 반환하는 게 나을수도 있겠네요

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

그게 아니어도 그냥 runCatching 정도로 잡아도 될듯합니다

Comment on lines +15 to +26
private val client: LibraryClient = Mockito.mock(LibraryClient::class.java)

@Before
fun setup() {
libraryRepository = LibraryRepositoryImpl(client)
}

@Test
fun `get Library Seat Status From Remote Test`() = runTest {
val mockLibraryStatus = LibraryTestUtil.mockLibrarySeatResponse()

Mockito.`when`(client.fetchRoomSeatStatus()).thenReturn(mockLibraryStatus)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

굳이 Mock을 사용할 필요가 있을까요? 인터페이스 다형성을 활용해보면 좋을 것 같아요

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

제가 테스트 코드 작성이 아직 미흡해서 기존 테스트 코드를 좀 차용했습니다..
추후에 좀 더 괜찮은 방법으로 테스트 코드를 작성해보도록 할게요!

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

넵 좋습니다.

Comment on lines 5 to 11
data class LibraryRoomBranchResponse (
val id: Int,
@SerializedName("name") val roomBranchName: String,
val alias: String,
val libraryCode: String,
val sortOrder: Int
)
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이거 난독화 걸리면 name 빼고 다른 프로퍼티는 난독화 안전하지 않습니다. 혹시 모르니 수정해주시는걸 권장합니다.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

cf: 제 리뷰 코멘트와 같은 맥락입니다

return Retrofit.Builder()
.client(okHttpClient)
.baseUrl("https://library.konkuk.ac.kr/pyxis-api/")
.addConverterFactory(GsonConverterFactory.create())
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@mwy3055 null 안정성 생각하면 kotlinx.serialization 적용하는것도...?

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 null 때문에 티켓도 만들긴 했습니다. 오래전부터 인지하고 있던 문제였는데요

kotlinx.serialization 좀 찾아보니까 서버에서 값이 안 오면 변환할 때 exception이 나는 거 같은데, 예측할 수 없는 NPE보다는 이게 나은 거 같네요. 라이브러리 바꿀 게 많네요 ㅋㅋ

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ

이것도 차근차근 해봅시다(그리고 하루컷 나고 그러는거 아닌가)

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 테스트는 작성한 의도가 있을까요?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 테스트 코드도 기존 코드를 차용한 것 입니다..
제가 이해한 테스트 코드 진행 순서인데, 이게 맞을까요?

  1. initService에서 createService 함수를 통해 테스트용 서비스 변수를 초기화
  2. @test 함수에서 enqueueResponse로 service의 함수를 호출했을 때 반환할 응답으로 json 파일을 지정
  3. mockWebServer의 takeRequest()를 통해 service가 의도대로 동작했는지 확인
  4. assert로 반환된 값이랑 예상 값이랑 비교

Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mockWebServer에서 response를 테스트 하는것은 저희가 직접 정해주는 값을 넣고 그 값이 객체로 잘 역직렬화되는지를 확인하는 것과 같은데, 이런 테스트를 작성해서 얻을 수 있는 효험이 어떤 것이 있을지 생각해보면 좋을 것 같아요. 추가로 리스폰스가 변경이 되면 json 파일도 변경이 되어야 하는 등 유지보수를 해야하는데 그걸 감안하더라도 의미가 있는지까지 같이!

Copy link
Member

@mwy3055 mwy3055 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이정도면 괜찮은 것 같습니다 👍

Comment on lines 5 to 14
data class LibrarySeatResponse(
@SerializedName("success")
val success: Boolean,
@SerializedName("code")
val code: String,
@SerializedName("message")
val message: String,
@SerializedName("data")
val data: LibraryRoomListResponse
)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@SerializedName을 자동으로 붙여주는 gradle 플러그인을 만들어 보면..? 그냥 아이디어입니다 ㅎㅎ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants