Conversation
Walkthrough
Changes
Sequence Diagram(s)sequenceDiagram
autonumber
actor U as User
participant VM as ProfileUpdateViewModel
participant Repo as ProfileRepository
participant DS as AconAppRemoteDataSource
participant NoAuth as AconAppNoAuthApi
participant Up as FileUploadApi
participant ProfAPI as ProfileRemoteDataSource/Api
participant Srv as Server(Object Storage & App)
U->>VM: 저장 클릭
VM->>Repo: updateProfile(newProfile)
alt 이미지가 로컬 content Uri
Repo->>DS: getPresignedUrl(request:imageType, fileName)
DS->>NoAuth: POST /images/presigned-url
NoAuth-->>DS: PresignedUrlResponse(fileUrl, preSignedUrl)
DS-->>Repo: PresignedUrlResponse
Repo->>Up: PUT preSignedUrl with RequestBody(bytes)
Up->>Srv: PUT to Object Storage
Srv-->>Up: 200
Repo->>ProfAPI: updateProfile(profileImage = fileUrl, ...)
else 이미지 변경 없음/원격 URL
Repo->>ProfAPI: updateProfile(existing image, ...)
end
ProfAPI->>Srv: PATCH /profile
Srv-->>ProfAPI: 200/에러
ProfAPI-->>Repo: 결과
Repo-->>VM: 성공/실패
VM-->>U: 네비게이션 뒤로 or 실패 토스트
Estimated code review effort🎯 4 (Complex) | ⏱️ ~70 minutes Possibly related PRs
Poem
Pre-merge checks and finishing touches❌ Failed checks (1 warning)
✅ Passed checks (2 passed)
✨ Finishing touches
🧪 Generate unit tests
Comment |
There was a problem hiding this comment.
Actionable comments posted: 8
♻️ Duplicate comments (1)
core/data/src/main/kotlin/com/acon/core/data/dto/request/GetPresignedUrlRequest.kt (1)
7-11: ImageType 직렬화 전제 재언급이 DTO가 ImageType을 직렬화하므로, ImageType에 @serializable 및 모듈 플러그인 적용이 필요합니다. 상세는 ImageType.kt 코멘트 참고.
🧹 Nitpick comments (15)
core/data/src/main/kotlin/com/acon/core/data/dto/request/profile/UpdateProfileRequest.kt (1)
11-14: 속성명 일관성(선택) — image → profileImage 리네이밍서버 키가 profileImage라면 DTO 속성도 동일 명칭으로 맞추면 가독성이 올라갑니다. 영향 범위가 넓다면 보류 가능.
제안:
- @SerialName("profileImage") val image: String? + @SerialName("profileImage") val profileImage: String?호출부/매핑도 함께 정리 필요.
core/data/src/main/kotlin/com/acon/core/data/api/remote/ProfileApi.kt (1)
18-18: Retrofit 반환 타입 명시로 의도 드러내기응답 본문을 쓰지 않는다면 Unit 명시 또는 Response로 상태코드 접근을 고려하세요.
- suspend fun updateProfile(@Body updateProfileRequest: UpdateProfileRequest) + suspend fun updateProfile(@Body updateProfileRequest: UpdateProfileRequest): Unit- suspend fun validateNickname(@Query("nickname") nickname: String) + suspend fun validateNickname(@Query("nickname") nickname: String): Unit상태코드나 헤더가 필요하면 Response을 권장합니다.
Also applies to: 21-21
core/data/src/main/kotlin/com/acon/core/data/di/ApiModule.kt (1)
118-124: 대용량 업로드 대비 OkHttp 타임아웃/헤더 관리 확인S3 등 presigned 업로드는 기본 타임아웃(10s~)으로 실패할 수 있고, 불필요한 공통 헤더가 서명과 충돌할 수 있습니다. NoAuth 클라이언트에 한해 업로드용 별도 OkHttp 설정(연장 타임아웃, 헤더 최소화, 바디 로깅 금지)을 권장합니다.
필요 시 업로드 전용 Retrofit/Client 분리(예: @UploadNoAuth)로 운영 리스크를 줄이세요.
domain/src/main/java/com/acon/acon/domain/usecase/ValidateNicknameUseCase.kt (1)
15-21: 검증 로직 소폭 단순화 제안(선택)단일 정규식으로 길이/형식을 함께 검증하면 분기와 에러 매핑이 단순해집니다. 필요 시 유지보수성을 위해 현 구조 유지도 무방합니다.
core/data/src/main/kotlin/com/acon/core/data/dto/request/GetPresignedUrlRequest.kt (1)
9-11: originalFileName의 개인정보/경로 노출 위험단말 파일명(경로/사용자명 포함 가능)을 그대로 전송하면 불필요한 메타데이터가 저장/로그될 수 있습니다. 확장자만 보존하거나 난수/UUID 파일명으로 대체하는 방식을 권장합니다(서버 요구사항 허용 시).
core/data/src/main/kotlin/com/acon/core/data/datasource/remote/AconAppRemoteDataSource.kt (1)
19-25: 메서드 시그니처/책임 분리 제안현재는 성공/실패만 예외로 표출됩니다. 필요 시 업로드 응답 상태(예: ETag, Content-MD5)를 반환하도록 확장해도 좋습니다. 다만 지금 단계에선 현행 유지해도 무방합니다.
core/data/src/main/kotlin/com/acon/core/data/repository/ProfileRepositoryImpl.kt (1)
12-12: 불필요한 import 제거FileUploadApi는 이 파일에서 사용되지 않습니다. 삭제해 주세요.
-import com.acon.core.data.api.remote.noauth.FileUploadApifeature/profile/src/test/kotlin/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModelTest.kt (1)
461-462: 검증 대상 함수가 잘못되었습니다 — 닉네임 선택 변경 시 닉네임 유효성 호출 금지 검증 필요Text Selection으로 onNicknameInputChanged가 호출될 때는 ValidateNicknameUseCase가 호출되지 않아야 합니다. 현재는 ValidateBirthDateUseCase를 검증하고 있습니다.
- coVerify(exactly = 0) { validateBirthDateUseCase(any()) } + coVerify(exactly = 0) { validateNicknameUseCase(any()) }core/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt (3)
266-285: 원격 성공 시 캐시 저장 호출까지 검증 추가 권장현재는 결과만 검증합니다. cacheSavedSpots 호출 여부까지 확인하면 회귀 방지에 도움이 됩니다.
val actualResult = profileRepository.getSavedSpots().first() // Then assertEquals(expectedResult, actualResult) + coVerify(exactly = 1) { profileLocalDataSource.cacheSavedSpots(sampleSavedSpots) } + coVerify(exactly = 1) { profileRemoteDataSource.getSavedSpots() }
168-185: 변수 이름 섀도잉(naming shadowing) 정리 제안프로퍼티 getter
sampleNewProfile과 동일한 이름의 지역 변수val sampleNewProfile = sampleNewProfile는 혼동을 줍니다. 지역 변수 제거 또는 프로퍼티명 변경을 권장합니다.- val sampleNewProfile = sampleNewProfile + val profileToUpdate = sampleNewProfile ... - val actualResult = profileRepository.updateProfile(sampleNewProfile) + val actualResult = profileRepository.updateProfile(profileToUpdate)
114-147: 유사 테스트 설명 중복/명확성 개선 제안두 테스트가 모두 "로컬 없음 → 원격 호출" 시나리오를 다룹니다. 설명을 통일/정리하여 목적을 구분하면 가독성이 좋아집니다.
feature/profile/src/main/java/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModel.kt (4)
103-103: 생일 입력 유효성 검사 로직 개선 필요
isDigitsOnly()확장 함수를 사용하면 더 명확하고 간결한 코드가 됩니다.- if (input.text.any { it.isDigit().not() }) return@intent + if (!input.text.isDigitsOnly()) return@intent
234-241: 저장 버튼 활성화 조건 로직 단순화 필요현재
isSaveEnabled로직이 복잡하고 이해하기 어렵습니다. 조건을 더 명확하게 분리하면 유지보수성이 향상됩니다.val isSaveEnabled: Boolean - get() = ( - nicknameValidationStatus is NicknameValidationStatus.Available && - birthDateValidationStatus is BirthDateValidationStatus.Valid) || ( - profileImageInputStatus is ProfileImageInputStatus.Changed && - nicknameValidationStatus is NicknameValidationStatus.Idle && - birthDateValidationStatus is BirthDateValidationStatus.Valid - ) + get() { + val isNicknameValid = nicknameValidationStatus is NicknameValidationStatus.Available || + (nicknameValidationStatus is NicknameValidationStatus.Idle && + profileImageInputStatus is ProfileImageInputStatus.Changed) + + val isBirthDateValid = birthDateValidationStatus is BirthDateValidationStatus.Valid + + return isNicknameValid && isBirthDateValid + }
203-215: 프로필 업데이트 실패 시 상세 에러 처리 필요현재 모든 실패를 동일하게 처리하고 있습니다. 네트워크 오류, 서버 오류 등을 구분하여 사용자에게 더 명확한 피드백을 제공하는 것이 좋습니다.
실패 케이스별 에러 처리를 구현해 드릴까요? 예를 들어:
- 네트워크 오류: "네트워크 연결을 확인해 주세요"
- 서버 오류: "일시적인 오류가 발생했습니다. 잠시 후 다시 시도해 주세요"
- 유효성 검사 실패: 구체적인 실패 이유 표시
119-145: 생일 유효성 검사 로직 중복 제거 필요생일 입력 처리에서 중복된
reduce호출이 많습니다. 하나의reduce로 통합하면 더 효율적입니다.- if (input.text.isEmpty()) { - reduce { - state.copy(birthDateValidationStatus = BirthDateValidationStatus.Valid) - } - } else if (input.text.length in 1 until 8) { - reduce { - state.copy(birthDateValidationStatus = BirthDateValidationStatus.Idle) - } - } else if (input.text.length == 8) { - val localDate = input.text.toLocalDate() - if (localDate == null) - reduce { - state.copy(birthDateValidationStatus = BirthDateValidationStatus.Invalid) - } - else { - validateBirthDateUseCase(localDate).onSuccess { - reduce { - state.copy(birthDateValidationStatus = BirthDateValidationStatus.Valid) - } - }.onFailure { - reduce { - state.copy(birthDateValidationStatus = BirthDateValidationStatus.Invalid) - } - } - } - } + val validationStatus = when { + input.text.isEmpty() -> BirthDateValidationStatus.Valid + input.text.length in 1 until 8 -> BirthDateValidationStatus.Idle + input.text.length == 8 -> { + val localDate = input.text.toLocalDate() + if (localDate == null) { + BirthDateValidationStatus.Invalid + } else { + validateBirthDateUseCase(localDate) + .fold( + onSuccess = { BirthDateValidationStatus.Valid }, + onFailure = { BirthDateValidationStatus.Invalid } + ) + } + } + else -> state.birthDateValidationStatus + } + + reduce { + state.copy(birthDateValidationStatus = validationStatus) + }
📜 Review details
Configuration used: CodeRabbit UI
Review profile: CHILL
Plan: Pro
📒 Files selected for processing (22)
core/common/src/main/java/com/acon/acon/core/common/utils/DateExtensions.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/api/remote/ProfileApi.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/api/remote/noauth/AconAppNoAuthApi.kt(2 hunks)core/data/src/main/kotlin/com/acon/core/data/api/remote/noauth/FileUploadApi.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/datasource/remote/AconAppRemoteDataSource.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/di/ApiModule.kt(2 hunks)core/data/src/main/kotlin/com/acon/core/data/dto/request/GetPresignedUrlRequest.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/dto/request/profile/UpdateProfileRequest.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/dto/response/PresignedUrlResponse.kt(1 hunks)core/data/src/main/kotlin/com/acon/core/data/repository/ProfileRepositoryImpl.kt(2 hunks)core/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt(10 hunks)core/model/src/main/java/com/acon/acon/core/model/type/ImageType.kt(1 hunks)domain/src/main/java/com/acon/acon/domain/error/profile/UpdateProfileError.kt(1 hunks)domain/src/main/java/com/acon/acon/domain/error/profile/ValidateBirthDateError.kt(1 hunks)domain/src/main/java/com/acon/acon/domain/error/profile/ValidateNicknameError.kt(1 hunks)domain/src/main/java/com/acon/acon/domain/usecase/ValidateBirthDateUseCase.kt(1 hunks)domain/src/main/java/com/acon/acon/domain/usecase/ValidateNicknameUseCase.kt(2 hunks)feature/profile/src/main/java/com/acon/feature/profile/update/status/BirthDateValidationStatus.kt(1 hunks)feature/profile/src/main/java/com/acon/feature/profile/update/status/NicknameValidationStatus.kt(1 hunks)feature/profile/src/main/java/com/acon/feature/profile/update/status/ProfileImageInputStatus.kt(1 hunks)feature/profile/src/main/java/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModel.kt(1 hunks)feature/profile/src/test/kotlin/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModelTest.kt(1 hunks)
🧰 Additional context used
🧠 Learnings (3)
📚 Learning: 2025-09-19T04:19:20.229Z
Learnt from: ThirFir
PR: AconInc/ACON-Android#253
File: core/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt:273-277
Timestamp: 2025-09-19T04:19:20.229Z
Learning: ProfileRepositoryTest.kt의 updateProfileErrorScenarios()에서 UNSPECIFIED_SERVER_ERROR_CODE를 여러 에러 타입에 사용하는 것은 테스트용으로 의도된 것이며, 실제 서버 에러 코드가 확정되기 전의 임시적인 접근방식입니다.
Applied to files:
domain/src/main/java/com/acon/acon/domain/error/profile/UpdateProfileError.ktdomain/src/main/java/com/acon/acon/domain/error/profile/ValidateNicknameError.ktdomain/src/main/java/com/acon/acon/domain/error/profile/ValidateBirthDateError.ktcore/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt
📚 Learning: 2025-09-19T04:52:02.675Z
Learnt from: ThirFir
PR: AconInc/ACON-Android#254
File: app/src/main/java/com/acon/acon/navigation/nested/ProfileNavigationLegacy.kt:38-40
Timestamp: 2025-09-19T04:52:02.675Z
Learning: In ProfileNavigationLegacy.kt, the onNavigateToProfileUpdate callback is intentionally left as a placeholder (just returning navController) and will be implemented in a future PR according to ThirFir.
Applied to files:
feature/profile/src/main/java/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModel.kt
📚 Learning: 2025-09-19T04:19:12.297Z
Learnt from: ThirFir
PR: AconInc/ACON-Android#253
File: domain/src/main/java/com/acon/acon/domain/error/profile/ValidateNicknameError.kt:10-15
Timestamp: 2025-09-19T04:19:12.297Z
Learning: ValidateNicknameError의 InvalidFormat과 AlreadyExist 클래스에서 UNSPECIFIED_SERVER_ERROR_CODE(-1)를 사용하는 것은 테스트용으로 의도된 것입니다. 실제 서버 에러 코드는 나중에 적용될 예정입니다.
Applied to files:
domain/src/main/java/com/acon/acon/domain/error/profile/ValidateNicknameError.kt
🧬 Code graph analysis (3)
feature/profile/src/test/kotlin/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModelTest.kt (1)
domain/src/test/kotlin/com/acon/acon/domain/usecase/ValidateBirthDateUseCaseTest.kt (1)
validateBirthDateUseCase(14-80)
feature/profile/src/main/java/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModel.kt (1)
domain/src/test/kotlin/com/acon/acon/domain/usecase/ValidateBirthDateUseCaseTest.kt (1)
validateBirthDateUseCase(14-80)
core/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt (1)
core/data/src/test/java/com/acon/core/data/TestUtils.kt (1)
createErrorStream(12-16)
⏰ Context from checks skipped due to timeout of 90000ms. You can increase the timeout in your CodeRabbit configuration to a maximum of 15 minutes (900000ms). (1)
- GitHub Check: build
🔇 Additional comments (25)
domain/src/main/java/com/acon/acon/domain/error/profile/ValidateBirthDateError.kt (1)
10-10: 특정 에러 코드 값 할당 완료40053 값으로 특정 에러 코드가 정상적으로 할당되었습니다. 이전의 UNSPECIFIED_SERVER_ERROR_CODE 사용에서 벗어나 명확한 에러 식별이 가능하게 되었습니다.
domain/src/main/java/com/acon/acon/domain/usecase/ValidateBirthDateUseCase.kt (2)
5-5: DI 지원을 위한 import 추가의존성 주입(DI) 지원을 위해 필요한 import가 적절히 추가되었습니다.
7-7: DI 지원을 위한 constructor annotation 추가@Inject 어노테이션이 primary constructor에 적절히 추가되어 의존성 주입을 지원합니다. ProfileUpdateViewModel에서 이 UseCase를 주입받아 사용할 수 있게 되었습니다.
core/data/src/main/kotlin/com/acon/core/data/api/remote/noauth/FileUploadApi.kt (1)
8-14: Presigned URL 업로드를 위한 간단하고 효과적인 API 정의Presigned URL 방식의 파일 업로드를 위한 API가 적절하게 정의되었습니다. @put과 @Body RequestBody를 사용하는 방식이 Presigned URL 업로드에 적합합니다.
core/data/src/main/kotlin/com/acon/core/data/dto/response/PresignedUrlResponse.kt (1)
6-10: Presigned URL 응답 DTO 구조가 적절함fileUrl과 presignedUrl 필드를 가진 DTO 구조가 Presigned URL 워크플로우에 적합하게 설계되었습니다. SerialName 매핑도 정확히 설정되었습니다.
core/common/src/main/java/com/acon/acon/core/common/utils/DateExtensions.kt (3)
7-9: 날짜 포맷터의 효율적인 lazy 초기화DateTimeFormatter를 lazy로 초기화하여 메모리 효율성과 성능을 고려한 좋은 구현입니다.
14-16: LocalDate to String 변환 확장 함수LocalDate를 yyyyMMdd 형식으로 변환하는 확장 함수가 간단하고 명확하게 구현되었습니다.
25-31: 안전한 String to LocalDate 변환예외 처리를 통해 파싱 실패 시 null을 반환하는 안전한 구현입니다. DateTimeParseException을 적절히 처리하여 견고성을 확보했습니다.
feature/profile/src/main/java/com/acon/feature/profile/update/status/NicknameValidationStatus.kt (1)
3-10: 닉네임 검증 상태를 위한 적절한 sealed interface 설계프로필 업데이트 기능에 필요한 모든 닉네임 검증 상태가 포함되어 있으며, 다른 status 클래스들(BirthDateValidationStatus, ProfileImageInputStatus)과 일관된 패턴을 따르고 있습니다.
domain/src/main/java/com/acon/acon/domain/error/profile/UpdateProfileError.kt (3)
8-8: 기존 에러 코드의 명확한 숫자 값 할당기존 에러들에 대해 UNSPECIFIED_SERVER_ERROR_CODE에서 명확한 숫자 에러 코드(40901, 40051, 40053)로 업데이트되어 에러 식별과 처리가 개선되었습니다.
Also applies to: 11-11, 14-14
16-24: 이미지 업로드 관련 새로운 에러 타입 추가Presigned URL 기반 이미지 업로드 기능에 필요한 새로운 에러 타입들이 적절한 에러 코드와 함께 추가되었습니다:
- InvalidBucketImagePath (40052): S3 버킷 경로 관련 에러
- InvalidImageType (40045): 이미지 타입 검증 에러
- InternalServerError (50005): 서버 내부 에러
이미지 업로드 워크플로우에서 발생할 수 있는 주요 에러 케이스들을 잘 포괄하고 있습니다.
30-33: createErrorInstances에 새로운 에러 타입 추가새로 추가된 에러 타입들이 createErrorInstances 메서드에 적절히 포함되어 에러 매핑이 완전하게 처리됩니다.
feature/profile/src/main/java/com/acon/feature/profile/update/status/ProfileImageInputStatus.kt (1)
3-6: 프로필 이미지 입력 상태를 위한 간결한 sealed interface프로필 이미지의 변경 여부를 나타내는 간단하고 명확한 상태 타입입니다. 다른 status 파일들과 일관된 패턴을 따르고 있어 코드 일관성이 좋습니다.
core/data/src/main/kotlin/com/acon/core/data/dto/request/profile/UpdateProfileRequest.kt (2)
24-27: Custom 이미지 URL이 로컬 URI일 가능성 — 사전 업로드 보장 필요ProfileImageStatus.Custom.url이 content:// 혹은 file:// 로컬 URI라면 서버로 그대로 전송되니, 사전 업로드 후 presigned 응답의 fileUrl을 세팅했는지 확인이 필요합니다.
레포지토리에서 업로드 후 Profile 모델의 image.url을 fileUrl로 치환하는지 테스트로 보강 부탁드립니다(로컬 URI 입력 → 요청 페이로드에 원격 URL 포함).
9-14: 해결 — Retrofit이 kotlinx.serialization 컨버터로 구성되어 있습니다core/data/src/main/kotlin/com/acon/core/data/di/NetworkModule.kt에서 com.jakewharton.retrofit2.converter.kotlinx.serialization.asConverterFactory를 import하고 json.asConverterFactory("application/json".toMediaType())를 addConverterFactory로 등록하고 있습니다 (라인 14, 126, 140, 156, 171). UpdateProfileRequest의 @serializable 사용은 Retrofit 설정과 호환됩니다.
core/data/src/main/kotlin/com/acon/core/data/api/remote/noauth/AconAppNoAuthApi.kt (1)
18-21: 엔드포인트 스펙 정합성 확인POST /api/v1/images/presigned-url의 요청/응답(JSON 키, enum 문자열)과 서버 스펙이 1:1로 일치하는지 점검해 주세요(특히 ImageType 직렬화).
서버가 기대하는 키/값이 다르면 @SerialName으로 고정하거나 커스텀 직렬화를 적용해야 합니다.
domain/src/main/java/com/acon/acon/domain/usecase/ValidateNicknameUseCase.kt (1)
28-30: 상수 도입 좋습니다MAX_NICKNAME_LENGTH 공개 상수화로 UI/테스트 재사용성이 좋아졌습니다.
feature/profile/src/main/java/com/acon/feature/profile/update/status/BirthDateValidationStatus.kt (1)
3-7: data object는 Kotlin 1.9+ 필요 — Kotlin 버전 확인 필요data object는 Kotlin 1.9 이상에서만 지원됩니다; 검증 스크립트 출력이 비어 있어 저장소의 Kotlin 버전을 확인하지 못했습니다. 빌드가 1.9 미만이면 아래처럼 data object를 object로 교체하세요.
-sealed interface BirthDateValidationStatus { - data object Idle: BirthDateValidationStatus - data object Valid: BirthDateValidationStatus - data object Invalid: BirthDateValidationStatus -} +sealed interface BirthDateValidationStatus { + object Idle: BirthDateValidationStatus + object Valid: BirthDateValidationStatus + object Invalid: BirthDateValidationStatus +}검증 요청: 루트/모듈별 Kotlin 버전(gradle.properties 또는 build.gradle(.kts) 내용) 출력 제공.
domain/src/main/java/com/acon/acon/domain/error/profile/ValidateNicknameError.kt (1)
10-14: 명시적 에러 코드 매핑 LGTMInvalidFormat=40051, AlreadyExist=40901로의 전환이 테스트/도메인 전반의 코드 일치에 도움 됩니다. 서버 스펙과 다른 코드가 배포 환경에 없는지만 마지막으로 한 번만 확인 부탁드립니다.
core/data/src/main/kotlin/com/acon/core/data/repository/ProfileRepositoryImpl.kt (1)
85-87: 캐시 업데이트 타이밍 LGTM원격 업데이트 성공 후에만 cacheProfile을 호출하고 있어 일관성이 유지됩니다.
feature/profile/src/test/kotlin/com/acon/feature/profile/update/viewmodel/ProfileUpdateViewModelTest.kt (2)
528-546: 입력 완료(valid) 시 플로우 검증 LGTM유즈케이스 성공 시 Valid로 전이되는 경로가 안정적으로 테스트되고 있습니다.
615-652: 프로필 이미지 입력 핸들링 테스트 커버리지 적절기본/사용자 지정 선택 시 상태 전이와 값 바인딩이 명확히 검증됩니다.
core/data/src/test/java/com/acon/core/data/repository/ProfileRepositoryTest.kt (3)
61-65: Context 주입 방식 합리적 (relaxed mock)Android 의존을 최소화하면서 새 생성자 시그니처를 잘 반영했습니다.
247-264: SavedSpots 캐시 히트 경로 테스트 LGTM로컬 히트 시 원격 미호출을 검증하고 있습니다.
302-316: 에러 코드 매핑 테스트 LGTM도메인 코드(40051/40901/40053/40052)와 일치합니다.
💻 Work Description
Summary by CodeRabbit