diff --git a/src/main/kotlin/com/petqua/application/member/MemberService.kt b/src/main/kotlin/com/petqua/application/member/MemberService.kt index 044d352b..ed9441e8 100644 --- a/src/main/kotlin/com/petqua/application/member/MemberService.kt +++ b/src/main/kotlin/com/petqua/application/member/MemberService.kt @@ -2,6 +2,7 @@ package com.petqua.application.member import com.petqua.application.member.dto.MemberAddProfileCommand import com.petqua.application.member.dto.MemberSignUpCommand +import com.petqua.application.member.dto.UpdateProfileCommand import com.petqua.application.token.AuthTokenInfo import com.petqua.application.token.TokenService import com.petqua.common.domain.findActiveByIdOrThrow @@ -19,6 +20,7 @@ import com.petqua.domain.member.nickname.NicknameWordRepository import com.petqua.domain.policy.bannedword.BannedWordRepository import com.petqua.domain.policy.bannedword.BannedWords import com.petqua.exception.member.MemberException +import com.petqua.exception.member.MemberExceptionType.ALREADY_EXIST_NICKNAME import com.petqua.exception.member.MemberExceptionType.FAILED_NICKNAME_GENERATION import com.petqua.exception.member.MemberExceptionType.HAS_SIGNED_UP_MEMBER import com.petqua.exception.member.MemberExceptionType.NOT_FOUND_MEMBER @@ -88,4 +90,23 @@ class MemberService( val bannedWords = BannedWords(bannedWordRepository.findAll()) bannedWords.validateContainingBannedWord(name) } + + fun updateProfile(command: UpdateProfileCommand) { + validateNickname(command.nickname, command.memberId) + val member = memberRepository.findActiveByIdOrThrow(command.memberId) { + MemberException(NOT_FOUND_MEMBER) + } + member.updateNickname(command.nickname) + } + + private fun validateNickname(nickname: Nickname, memberId: Long) { + validateContainingBannedWord(nickname.value) + validateDuplicatedNickname(nickname, memberId) + } + + private fun validateDuplicatedNickname(nickname: Nickname, memberId: Long) { + throwExceptionWhen(memberRepository.existsMemberByNicknameAndIdNot(nickname, memberId)) { + MemberException(ALREADY_EXIST_NICKNAME) + } + } } diff --git a/src/main/kotlin/com/petqua/application/member/dto/MemberDtos.kt b/src/main/kotlin/com/petqua/application/member/dto/MemberDtos.kt index 53d7941a..79185627 100644 --- a/src/main/kotlin/com/petqua/application/member/dto/MemberDtos.kt +++ b/src/main/kotlin/com/petqua/application/member/dto/MemberDtos.kt @@ -5,6 +5,7 @@ import com.petqua.domain.member.PetFish import com.petqua.domain.member.PetFishCount import com.petqua.domain.member.PetFishSex import com.petqua.domain.member.PetFishes +import com.petqua.domain.member.nickname.Nickname import java.time.YearMonth data class MemberSignUpCommand( @@ -51,3 +52,11 @@ data class PetFishAddCommand( ) } } + +data class UpdateProfileCommand( + val memberId: Long, + val nickname: Nickname, +) { + + constructor(memberId: Long, nickname: String) : this(memberId, Nickname.from(nickname)) +} diff --git a/src/main/kotlin/com/petqua/domain/member/MemberRepository.kt b/src/main/kotlin/com/petqua/domain/member/MemberRepository.kt index 6bc73d96..a0195e6c 100644 --- a/src/main/kotlin/com/petqua/domain/member/MemberRepository.kt +++ b/src/main/kotlin/com/petqua/domain/member/MemberRepository.kt @@ -17,5 +17,7 @@ interface MemberRepository : JpaRepository { fun existsMemberByNickname(nickname: Nickname): Boolean + fun existsMemberByNicknameAndIdNot(nickname: Nickname, id: Long): Boolean + fun existsMemberByAuthCredentialsId(authCredentialsId: Long): Boolean } diff --git a/src/main/kotlin/com/petqua/exception/member/MemberExceptionType.kt b/src/main/kotlin/com/petqua/exception/member/MemberExceptionType.kt index dbe9edda..9de13b67 100644 --- a/src/main/kotlin/com/petqua/exception/member/MemberExceptionType.kt +++ b/src/main/kotlin/com/petqua/exception/member/MemberExceptionType.kt @@ -25,6 +25,7 @@ enum class MemberExceptionType( INVALID_MEMBER_NICKNAME(BAD_REQUEST, "M16", "유효하지 않은 회원 닉네임입니다."), CONTAINING_BANNED_WORD_NAME(BAD_REQUEST, "M20", "이름에 금지 단어를 포함할 수 없습니다."), + ALREADY_EXIST_NICKNAME(BAD_REQUEST, "M21", "이미 사용 중인 닉네임입니다."), INVALID_MEMBER_STATE(INTERNAL_SERVER_ERROR, "M90", "유효하지 않은 회원 상태입니다."), FAILED_NICKNAME_GENERATION(LOOP_DETECTED, "M91", "서버에서 회원 닉네임을 생성하지 못했습니다.") diff --git a/src/main/kotlin/com/petqua/presentation/member/MemberController.kt b/src/main/kotlin/com/petqua/presentation/member/MemberController.kt index 463f07eb..1456769d 100644 --- a/src/main/kotlin/com/petqua/presentation/member/MemberController.kt +++ b/src/main/kotlin/com/petqua/presentation/member/MemberController.kt @@ -6,8 +6,8 @@ import com.petqua.common.config.SIGN_UP_TOKEN_SECURITY_SCHEME_KEY import com.petqua.domain.auth.Auth import com.petqua.domain.auth.LoginMember import com.petqua.domain.auth.SignUpGuest -import com.petqua.presentation.member.dto.MemberAddProfileRequest import com.petqua.presentation.member.dto.MemberSignUpRequest +import com.petqua.presentation.member.dto.UpdateProfileRequest import io.swagger.v3.oas.annotations.Operation import io.swagger.v3.oas.annotations.responses.ApiResponse import io.swagger.v3.oas.annotations.security.SecurityRequirement @@ -19,6 +19,7 @@ import org.springframework.http.HttpStatus.CREATED import org.springframework.http.ResponseCookie import org.springframework.http.ResponseEntity import org.springframework.web.bind.annotation.GetMapping +import org.springframework.web.bind.annotation.PatchMapping import org.springframework.web.bind.annotation.PostMapping import org.springframework.web.bind.annotation.RequestBody import org.springframework.web.bind.annotation.RequestMapping @@ -69,16 +70,29 @@ class MemberController( return ResponseEntity.noContent().build() } - @Operation(summary = "회원 물생활 프로필 입력 API", description = "회원의 추가적인 물생활 정보를 입력합니다") - @ApiResponse(responseCode = "204", description = "회원 물생활 프로필 입력 성공") +// @Operation(summary = "회원 물생활 프로필 입력 API", description = "회원의 추가적인 물생활 정보를 입력합니다") +// @ApiResponse(responseCode = "204", description = "회원 물생활 프로필 입력 성공") +// @SecurityRequirement(name = ACCESS_TOKEN_SECURITY_SCHEME_KEY) +// @PostMapping("/profiles") +// fun addProfile( +// @Auth loginMember: LoginMember, +// @RequestBody request: MemberAddProfileRequest, +// ): ResponseEntity { +// val command = request.toCommand(loginMember.memberId) +// memberService.addProfile(command) +// return ResponseEntity.noContent().build() +// } + + @Operation(summary = "회원 프로필 수정 API", description = "회원의 프로필 정보를 수정합니다") + @ApiResponse(responseCode = "204", description = "회원 프로필 수정 성공") @SecurityRequirement(name = ACCESS_TOKEN_SECURITY_SCHEME_KEY) - @PostMapping("/profiles") - fun addProfile( + @PatchMapping("/profiles") + fun updateProfile( @Auth loginMember: LoginMember, - @RequestBody request: MemberAddProfileRequest, + @RequestBody request: UpdateProfileRequest, ): ResponseEntity { val command = request.toCommand(loginMember.memberId) - memberService.addProfile(command) + memberService.updateProfile(command) return ResponseEntity.noContent().build() } } diff --git a/src/main/kotlin/com/petqua/presentation/member/dto/MemberDtos.kt b/src/main/kotlin/com/petqua/presentation/member/dto/MemberDtos.kt index 1335d662..b52ea114 100644 --- a/src/main/kotlin/com/petqua/presentation/member/dto/MemberDtos.kt +++ b/src/main/kotlin/com/petqua/presentation/member/dto/MemberDtos.kt @@ -3,6 +3,7 @@ package com.petqua.presentation.member.dto import com.petqua.application.member.dto.MemberAddProfileCommand import com.petqua.application.member.dto.MemberSignUpCommand import com.petqua.application.member.dto.PetFishAddCommand +import com.petqua.application.member.dto.UpdateProfileCommand import io.swagger.v3.oas.annotations.media.Schema import java.time.YearMonth @@ -89,3 +90,19 @@ data class PetFishAddRequest( ) val count: Int, ) + +data class UpdateProfileRequest( + @Schema( + description = "닉네임", + example = "펫쿠아" + ) + val nickname: String, +) { + + fun toCommand(memberId: Long): UpdateProfileCommand { + return UpdateProfileCommand( + memberId = memberId, + nickname = nickname, + ) + } +} diff --git a/src/test/kotlin/com/petqua/application/member/MemberServiceTest.kt b/src/test/kotlin/com/petqua/application/member/MemberServiceTest.kt index c63b32a7..b7297520 100644 --- a/src/test/kotlin/com/petqua/application/member/MemberServiceTest.kt +++ b/src/test/kotlin/com/petqua/application/member/MemberServiceTest.kt @@ -4,6 +4,7 @@ import com.ninjasquad.springmockk.SpykBean import com.petqua.application.member.dto.MemberAddProfileCommand import com.petqua.application.member.dto.MemberSignUpCommand import com.petqua.application.member.dto.PetFishAddCommand +import com.petqua.application.member.dto.UpdateProfileCommand import com.petqua.domain.auth.AuthCredentialsRepository import com.petqua.domain.fish.FishRepository import com.petqua.domain.member.FishTankRepository @@ -20,6 +21,7 @@ import com.petqua.domain.member.nickname.NicknameWordRepository import com.petqua.domain.policy.bannedword.BannedWord import com.petqua.domain.policy.bannedword.BannedWordRepository import com.petqua.exception.member.MemberException +import com.petqua.exception.member.MemberExceptionType.ALREADY_EXIST_NICKNAME import com.petqua.exception.member.MemberExceptionType.CONTAINING_BANNED_WORD_NAME import com.petqua.exception.member.MemberExceptionType.FAILED_NICKNAME_GENERATION import com.petqua.exception.member.MemberExceptionType.HAS_SIGNED_UP_MEMBER @@ -30,6 +32,7 @@ import com.petqua.exception.member.MemberExceptionType.INVALID_MEMBER_FISH_TANK_ import com.petqua.exception.member.MemberExceptionType.INVALID_MEMBER_PET_FISH import com.petqua.exception.member.MemberExceptionType.INVALID_MEMBER_PET_FISH_COUNT import com.petqua.exception.member.MemberExceptionType.NOT_FOUND_MEMBER +import com.petqua.test.DataCleaner import com.petqua.test.fixture.authCredentials import com.petqua.test.fixture.fish import com.petqua.test.fixture.member @@ -57,6 +60,7 @@ class MemberServiceTest( private val fishRepository: FishRepository, private val petFishRepository: PetFishRepository, private val fishTankRepository: FishTankRepository, + private val dataCleaner: DataCleaner, @SpykBean private val nicknameGenerator: NicknameGenerator, ) : BehaviorSpec({ @@ -444,4 +448,69 @@ class MemberServiceTest( } } } + + Given("프로필 수정을 할 때") { + val member = memberRepository.save(member(nickname = "닉네임")) + bannedWordRepository.save(BannedWord(word = "금지 단어")) + + When("닉네임을 입력하면") { + val command = UpdateProfileCommand( + memberId = member.id, + nickname = "변경된 닉네임", + ) + memberService.updateProfile(command) + + Then("닉네임을 수정한다") { + val updatedMember = memberRepository.findById(member.id).get() + + assertSoftly { + updatedMember.nickname.value shouldBe "변경된 닉네임" + } + } + } + + When("닉네임에 부적절한 단어가 들어가면") { + val command = UpdateProfileCommand( + memberId = member.id, + nickname = "금지 단어", + ) + + Then("예외를 던진다") { + shouldThrow { + memberService.updateProfile(command) + }.exceptionType() shouldBe CONTAINING_BANNED_WORD_NAME + } + } + + When("이미 다른 회원이 사용중인 닉네임이라면") { + memberRepository.save(member(nickname = "변경된 닉네임")) + val command = UpdateProfileCommand( + memberId = member.id, + nickname = "변경된 닉네임", + ) + + Then("예외를 던진다") { + shouldThrow { + memberService.updateProfile(command) + }.exceptionType() shouldBe ALREADY_EXIST_NICKNAME + } + } + + When("회원이 존재하지 않으면") { + val command = UpdateProfileCommand( + memberId = Long.MAX_VALUE, + nickname = "변경된 닉네임", + ) + + Then("예외를 던진다") { + shouldThrow { + memberService.updateProfile(command) + }.exceptionType() shouldBe NOT_FOUND_MEMBER + } + } + } + + afterContainer { + dataCleaner.clean() + } }) diff --git a/src/test/kotlin/com/petqua/presentation/member/MemberControllerSteps.kt b/src/test/kotlin/com/petqua/presentation/member/MemberControllerSteps.kt index db4bea23..5ec1978c 100644 --- a/src/test/kotlin/com/petqua/presentation/member/MemberControllerSteps.kt +++ b/src/test/kotlin/com/petqua/presentation/member/MemberControllerSteps.kt @@ -2,6 +2,7 @@ package com.petqua.presentation.member import com.petqua.presentation.member.dto.MemberAddProfileRequest import com.petqua.presentation.member.dto.MemberSignUpRequest +import com.petqua.presentation.member.dto.UpdateProfileRequest import io.restassured.module.kotlin.extensions.Extract import io.restassured.module.kotlin.extensions.Given import io.restassured.module.kotlin.extensions.Then @@ -59,3 +60,21 @@ fun requestAddProfile( response() } } + +fun requestUpdateProfile( + request: UpdateProfileRequest, + accessToken: String, +): Response { + return Given { + log().all() + contentType(APPLICATION_JSON_VALUE) + body(request) + auth().preemptive().oauth2(accessToken) + } When { + patch("/members/profiles") + } Then { + log().all() + } Extract { + response() + } +} diff --git a/src/test/kotlin/com/petqua/presentation/member/MemberControllerTest.kt b/src/test/kotlin/com/petqua/presentation/member/MemberControllerTest.kt index 85760c6f..04b8c691 100644 --- a/src/test/kotlin/com/petqua/presentation/member/MemberControllerTest.kt +++ b/src/test/kotlin/com/petqua/presentation/member/MemberControllerTest.kt @@ -2,12 +2,12 @@ package com.petqua.presentation.member import com.petqua.common.domain.findByIdOrThrow import com.petqua.common.exception.ExceptionResponse +import com.petqua.domain.auth.Authority +import com.petqua.domain.auth.token.AuthTokenProvider import com.petqua.domain.fish.FishRepository import com.petqua.domain.member.FishTankRepository import com.petqua.domain.member.MemberRepository import com.petqua.domain.member.PetFishRepository -import com.petqua.domain.member.PetFishSex -import com.petqua.domain.member.TankSize import com.petqua.domain.member.nickname.NicknameWord import com.petqua.domain.member.nickname.NicknameWordRepository import com.petqua.domain.policy.bannedword.BannedWord @@ -15,12 +15,11 @@ import com.petqua.domain.policy.bannedword.BannedWordRepository import com.petqua.exception.member.MemberExceptionType import com.petqua.exception.member.MemberExceptionType.CONTAINING_BANNED_WORD_NAME import com.petqua.exception.member.MemberExceptionType.HAS_SIGNED_UP_MEMBER -import com.petqua.presentation.member.dto.MemberAddProfileRequest +import com.petqua.exception.member.MemberExceptionType.NOT_FOUND_MEMBER import com.petqua.presentation.member.dto.MemberSignUpRequest -import com.petqua.presentation.member.dto.PetFishAddRequest +import com.petqua.presentation.member.dto.UpdateProfileRequest import com.petqua.test.ApiTestConfig -import com.petqua.test.fixture.fish -import com.petqua.test.fixture.memberAddProfileRequest +import com.petqua.test.fixture.member import io.kotest.assertions.assertSoftly import io.kotest.matchers.shouldBe import io.kotest.matchers.shouldNotBe @@ -29,10 +28,9 @@ import org.springframework.http.HttpHeaders import org.springframework.http.HttpHeaders.AUTHORIZATION import org.springframework.http.HttpStatus.BAD_REQUEST import org.springframework.http.HttpStatus.CREATED +import org.springframework.http.HttpStatus.NOT_FOUND import org.springframework.http.HttpStatus.NO_CONTENT -import java.time.LocalDate -import java.time.YearMonth -import kotlin.Long.Companion.MIN_VALUE +import java.util.* class MemberControllerTest( private val nicknameWordRepository: NicknameWordRepository, @@ -41,6 +39,7 @@ class MemberControllerTest( private val fishRepository: FishRepository, private val petFishRepository: PetFishRepository, private val fishTankRepository: FishTankRepository, + private val authTokenProvider: AuthTokenProvider, ) : ApiTestConfig() { init { @@ -132,69 +131,207 @@ class MemberControllerTest( } } } - - Given("회원 물생활 프로필을 등록할 때") { - nicknameWordRepository.saveAll( - listOf( - NicknameWord(word = "펫쿠아"), - NicknameWord(word = "물고기"), - ) - ) +// +// Given("회원 물생활 프로필을 등록할 때") { +// nicknameWordRepository.saveAll( +// listOf( +// NicknameWord(word = "펫쿠아"), +// NicknameWord(word = "물고기"), +// ) +// ) +// bannedWordRepository.saveAll( +// listOf( +// BannedWord(word = "금지"), +// BannedWord(word = "단어") +// ) +// ) +// val fish = fishRepository.save(fish()) +// +// val accessToken = signInAsMember().accessToken +// val memberId = getMemberIdByAccessToken(accessToken) +// +// When("어항과 수조, 반려어 등 정보를 입력하면") { +// val request = MemberAddProfileRequest( +// fishTankName = "펫쿠아 어항", +// installationDate = YearMonth.of(2024, 3), +// fishTankSize = "TANK_1", +// fishLifeYear = 1, +// petFishes = listOf( +// PetFishAddRequest( +// fishId = fish.id, +// sex = "FEMALE", +// count = 1 +// ) +// ) +// ) +// +// val response = requestAddProfile(request, accessToken) +// +// Then("회원의 물생활 정보가 저장된다") { +// assertSoftly { +// response.statusCode shouldBe NO_CONTENT.value() +// +// val member = memberRepository.findByIdOrThrow(memberId) +// member.fishTankCount shouldBe 1 +// member.fishLifeYear.value shouldBe 1 +// +// val fishTank = fishTankRepository.findByMemberId(member.id)[0] +// fishTank.memberId shouldBe member.id +// fishTank.name.value shouldBe "펫쿠아 어항" +// fishTank.installationDate shouldBe LocalDate.of(2024, 3, 1) +// fishTank.size shouldBe TankSize.TANK_1 +// +// val petFish = petFishRepository.findByFishTankId(fishTank.id)[0] +// petFish.memberId shouldBe member.id +// petFish.fishId shouldBe fish.id +// petFish.fishTankId shouldBe fishTank.id +// petFish.sex shouldBe PetFishSex.FEMALE +// petFish.count.value shouldBe 1 +// } +// } +// } +// +// When("수조 이름으로 부적절한 단어를 입력하면") { +// val request = memberAddProfileRequest(fishTankName = "금지단어포함이름") +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe CONTAINING_BANNED_WORD_NAME.errorMessage() +// } +// } +// } +// +// When("유효하지 않은 물생활 경력을 입력하면") { +// val request = memberAddProfileRequest(fishLifeYear = -1) +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_LIFE_YEAR.errorMessage() +// } +// } +// } +// +// When("수조 이름 정책을 위반해서 입력하면") { +// val request = memberAddProfileRequest(fishTankName = "열 여 덟 자 이 상 으 로 긴 어 항 이 름") +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_TANK_NAME.errorMessage() +// } +// } +// } +// +// When("존재하지 않는 수조 크기를 입력하면") { +// val request = memberAddProfileRequest(fishTankSize = "TANK_100") +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_TANK_SIZE.errorMessage() +// } +// } +// } +// +// When("존재하지 않는 반려어 id를 입력하면") { +// val request = memberAddProfileRequest( +// petFishes = listOf( +// PetFishAddRequest( +// fishId = MIN_VALUE, +// sex = "FEMALE", +// count = 1 +// ) +// ) +// ) +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_PET_FISH.errorMessage() +// } +// } +// } +// +// When("존재하지 않는 반려어 성별을 입력하면") { +// val request = memberAddProfileRequest( +// petFishes = listOf( +// PetFishAddRequest( +// fishId = MIN_VALUE, +// sex = "수컷", +// count = 1 +// ) +// ) +// ) +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_SEX.errorMessage() +// } +// } +// } +// +// When("유효하지 않은 반려어 마릿수를 입력하면") { +// val request = memberAddProfileRequest( +// petFishes = listOf( +// PetFishAddRequest( +// fishId = MIN_VALUE, +// sex = "FEMALE", +// count = -1 +// ) +// ) +// ) +// val response = requestAddProfile(request, accessToken) +// +// Then("예외를 응답한다") { +// val errorResponse = response.`as`(ExceptionResponse::class.java) +// assertSoftly(response) { +// statusCode shouldBe BAD_REQUEST.value() +// errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_PET_FISH_COUNT.errorMessage() +// } +// } +// } +// } + + Given("회원 프로필을 수정할 때") { + val accessToken = signInAsMember().accessToken bannedWordRepository.saveAll( listOf( - BannedWord(word = "금지"), - BannedWord(word = "단어") + BannedWord(word = "금지 단어"), ) ) - val fish = fishRepository.save(fish()) - - val accessToken = signInAsMember().accessToken - val memberId = getMemberIdByAccessToken(accessToken) - - When("어항과 수조, 반려어 등 정보를 입력하면") { - val request = MemberAddProfileRequest( - fishTankName = "펫쿠아 어항", - installationDate = YearMonth.of(2024, 3), - fishTankSize = "TANK_1", - fishLifeYear = 1, - petFishes = listOf( - PetFishAddRequest( - fishId = fish.id, - sex = "FEMALE", - count = 1 - ) - ) - ) - val response = requestAddProfile(request, accessToken) + When("닉네임을 입력하면") { + val request = UpdateProfileRequest(nickname = "변경된 닉네임") + val response = requestUpdateProfile(request, accessToken) - Then("회원의 물생활 정보가 저장된다") { + Then("회원의 닉네임을 수정한다") { assertSoftly { response.statusCode shouldBe NO_CONTENT.value() - val member = memberRepository.findByIdOrThrow(memberId) - member.fishTankCount shouldBe 1 - member.fishLifeYear.value shouldBe 1 - - val fishTank = fishTankRepository.findByMemberId(member.id)[0] - fishTank.memberId shouldBe member.id - fishTank.name.value shouldBe "펫쿠아 어항" - fishTank.installationDate shouldBe LocalDate.of(2024, 3, 1) - fishTank.size shouldBe TankSize.TANK_1 - - val petFish = petFishRepository.findByFishTankId(fishTank.id)[0] - petFish.memberId shouldBe member.id - petFish.fishId shouldBe fish.id - petFish.fishTankId shouldBe fishTank.id - petFish.sex shouldBe PetFishSex.FEMALE - petFish.count.value shouldBe 1 + val updatedMember = memberRepository.findByIdOrThrow(1L) + updatedMember.nickname.value shouldBe "변경된 닉네임" } } } - When("수조 이름으로 부적절한 단어를 입력하면") { - val request = memberAddProfileRequest(fishTankName = "금지단어포함이름") - val response = requestAddProfile(request, accessToken) + When("닉네임에 부적절한 단어가 들어가면") { + val request = UpdateProfileRequest(nickname = "금지 단어") + val response = requestUpdateProfile(request, accessToken) Then("예외를 응답한다") { val errorResponse = response.`as`(ExceptionResponse::class.java) @@ -205,104 +342,34 @@ class MemberControllerTest( } } - When("유효하지 않은 물생활 경력을 입력하면") { - val request = memberAddProfileRequest(fishLifeYear = -1) - val response = requestAddProfile(request, accessToken) - - Then("예외를 응답한다") { - val errorResponse = response.`as`(ExceptionResponse::class.java) - assertSoftly(response) { - statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_LIFE_YEAR.errorMessage() - } - } - } - - When("수조 이름 정책을 위반해서 입력하면") { - val request = memberAddProfileRequest(fishTankName = "열 여 덟 자 이 상 으 로 긴 어 항 이 름") - val response = requestAddProfile(request, accessToken) - - Then("예외를 응답한다") { - val errorResponse = response.`as`(ExceptionResponse::class.java) - assertSoftly(response) { - statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_TANK_NAME.errorMessage() - } - } - } - - When("존재하지 않는 수조 크기를 입력하면") { - val request = memberAddProfileRequest(fishTankSize = "TANK_100") - val response = requestAddProfile(request, accessToken) - - Then("예외를 응답한다") { - val errorResponse = response.`as`(ExceptionResponse::class.java) - assertSoftly(response) { - statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_TANK_SIZE.errorMessage() - } - } - } - - When("존재하지 않는 반려어 id를 입력하면") { - val request = memberAddProfileRequest( - petFishes = listOf( - PetFishAddRequest( - fishId = MIN_VALUE, - sex = "FEMALE", - count = 1 - ) - ) - ) - val response = requestAddProfile(request, accessToken) - - Then("예외를 응답한다") { - val errorResponse = response.`as`(ExceptionResponse::class.java) - assertSoftly(response) { - statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_PET_FISH.errorMessage() - } - } - } - - When("존재하지 않는 반려어 성별을 입력하면") { - val request = memberAddProfileRequest( - petFishes = listOf( - PetFishAddRequest( - fishId = MIN_VALUE, - sex = "수컷", - count = 1 - ) - ) - ) - val response = requestAddProfile(request, accessToken) + When("이미 다른 회원이 사용중인 닉네임이라면") { + memberRepository.save(member(nickname = "변경된 닉네임")) + val request = UpdateProfileRequest(nickname = "변경된 닉네임") + val response = requestUpdateProfile(request, accessToken) Then("예외를 응답한다") { val errorResponse = response.`as`(ExceptionResponse::class.java) assertSoftly(response) { statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_FISH_SEX.errorMessage() + errorResponse.message shouldBe MemberExceptionType.ALREADY_EXIST_NICKNAME.errorMessage() } } } - When("유효하지 않은 반려어 마릿수를 입력하면") { - val request = memberAddProfileRequest( - petFishes = listOf( - PetFishAddRequest( - fishId = MIN_VALUE, - sex = "FEMALE", - count = -1 - ) - ) - ) - val response = requestAddProfile(request, accessToken) + When("회원이 존재하지 않으면") { + val request = UpdateProfileRequest(nickname = "변경된 닉네임") + val accessTokenOfNoExistMember = authTokenProvider.createLoginAuthToken( + memberId = Long.MAX_VALUE, + authority = Authority.MEMBER, + issuedDate = Date() + ).getAccessToken() + val response = requestUpdateProfile(request, accessTokenOfNoExistMember) Then("예외를 응답한다") { val errorResponse = response.`as`(ExceptionResponse::class.java) assertSoftly(response) { - statusCode shouldBe BAD_REQUEST.value() - errorResponse.message shouldBe MemberExceptionType.INVALID_MEMBER_PET_FISH_COUNT.errorMessage() + statusCode shouldBe NOT_FOUND.value() + errorResponse.message shouldBe NOT_FOUND_MEMBER.errorMessage() } } }