Skip to content

Commit

Permalink
[KAN-109] 유저 통합 + 유닛 테스트 코드 (#80)
Browse files Browse the repository at this point in the history
  • Loading branch information
sinkyoungdeok authored May 30, 2024
1 parent 9d74eb4 commit cec9434
Show file tree
Hide file tree
Showing 16 changed files with 1,124 additions and 23 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -21,27 +21,26 @@ class SignUpUserService(
@Transactional
fun signUpUser(request: SignUpUserRequest): SignUpUserResponse {
with(request) {
userRepository.findByNicknameOrEmail(nickname, email)?.let {
if (it.nickname == nickname) {
throw DuplicateUserNicknameException()
}
val user = userRepository.findByNicknameOrEmail(nickname, email)
if (user?.nickname == nickname) {
throw DuplicateUserNicknameException()
}

if (it.email == email) {
throw DuplicateUserEmailException()
}
if (user?.email == email) {
throw DuplicateUserEmailException()
}

val user = userRepository.save(toEntity())
val newUser = userRepository.save(toEntity())

val token = tokenProvider.createTokens(email, user.roles)
val token = tokenProvider.createTokens(email, newUser.roles)

redisRepository.setValue(
redisRepository.REFRESH_PREFIX + email,
token.refreshToken,
tokenProvider.refreshTokenValidityInMilliseconds,
TimeUnit.MILLISECONDS
)
return SignUpUserResponse(user = user, token = token)
return SignUpUserResponse(user = newUser, token = token)
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -21,8 +21,7 @@ class UpdateUserService(

@Transactional
fun updatePassword(request: UpdatePasswordRequest) {
val user = userRepository.findByEmail(request.email)
?: throw NotFoundUserEmailException()
val user = userRepository.findByEmail(request.email) ?: throw NotFoundUserEmailException()
val token = redisRepository
.getValue(
"user:${request.email}:${EmailSendType
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ class UpdateUserController(
@Valid @RequestBody
request: UpdateUserRequest
): CommonResponse<UpdateUserResponse> {
updateUserService.updateUser(request, principal.name)
return CommonResponse.success()
val response = updateUserService.updateUser(request, principal.name)
return CommonResponse.success(response)
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -15,23 +15,23 @@ data class SignUpUserRequest(
@field:Email(message = "이메일 형식이 아닙니다.")
@field:NotBlank(message = "아이디를 입력해 주세요.")
@ApiModelProperty(value = "이메일 아이디", example = "test@gmail.com", required = true)
val email: String = "",
val email: String,

@field:Size(min = 8, max = 20, message = "8~20자 이내로 입력해 주세요.")
@field:NotBlank(message = "비밀번호를 입력해 주세요.")
@ApiModelProperty(value = "비밀번호", example = "test12!@", required = true)
val password: String = "",
val password: String,

@field:NotBlank(message = "닉네임을 입력해 주세요.")
@ApiModelProperty(value = "닉네임", example = "닉네임", required = true)
val nickname: String = "",
val nickname: String,

@ApiModelProperty(
value = "프로필 이미지 URL",
example = "https://test.com/test.jpg",
required = true
)
val profileImageUrl: String = ""
val profileImageUrl: String
) {

fun toEntity() = User(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,6 @@ data class UpdatePasswordRequest(
@ApiModelProperty(value = "이메일", example = "test@test.com", required = true)
val email: String,
@field:NotEmpty(message = "비밀번호는 필수 값 입니다.")
@field:Pattern(
regexp = "^(?=.*[A-Z])(?=.*[a-z])(?=.*\\d)(?=.*[\\W_])[A-Za-z\\d\\W_]{8,16}\$",
message = "영소문자, 영대문자, 숫자, 특수문자가 포함된 8~16자 비밀번호"
)
@ApiModelProperty(value = "비밀번호", example = "Test1234!", required = true)
val password: String,
@field:NotEmpty(message = "변경 토큰은 필수 값 입니다.")
Expand Down
8 changes: 7 additions & 1 deletion src/test/kotlin/com/restaurant/be/common/util/UserUtil.kt
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.restaurant.be.common.util

import com.restaurant.be.common.password.PasswordService
import com.restaurant.be.user.domain.entity.User
import com.restaurant.be.user.repository.UserRepository
import org.springframework.security.core.authority.SimpleGrantedAuthority
Expand All @@ -8,7 +9,12 @@ import org.springframework.security.web.authentication.preauth.PreAuthenticatedA
import java.security.Principal

fun setUpUser(email: String, userRepository: UserRepository): User {
val user = User(email = email, profileImageUrl = "")
val user = User(
email = email,
profileImageUrl = "",
nickname = "nickname",
password = "password".run(PasswordService::hashPassword)
)
userRepository.save(user)

SecurityContextHolder.getContext().authentication =
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
package com.restaurant.be.user.presentation.controller

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.restaurant.be.common.CustomDescribeSpec
import com.restaurant.be.common.IntegrationTest
import com.restaurant.be.common.PageDeserializer
import com.restaurant.be.common.response.CommonResponse
import com.restaurant.be.common.util.setUpUser
import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto
import com.restaurant.be.user.presentation.dto.CheckNicknameResponse
import com.restaurant.be.user.repository.UserRepository
import io.kotest.matchers.shouldBe
import org.springframework.data.domain.Page
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.transaction.annotation.Transactional
import java.nio.charset.Charset

@IntegrationTest
@Transactional
class CheckNicknameControllerTest(
private val mockMvc: MockMvc,
private val userRepository: UserRepository
) : CustomDescribeSpec() {
private val baseUrl = "/v1/users"
private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply {
val module = SimpleModule()
module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java))
this.registerModule(module)
}

init {
beforeEach {
setUpUser("test@gmail.com", userRepository)
}

describe("#checkNickname basic test") {
it("when nickname is not used should return isDuplicate false") {
// given
val nickname = "test"

// when
val result = mockMvc.perform(
get("$baseUrl/check-nickname")
.param("nickname", nickname)
).also {
println(it.andReturn().response.contentAsString)
}
.andExpect(status().isOk)
.andExpect(jsonPath("$.result").value("SUCCESS"))
.andReturn()

val responseContent = result.response.getContentAsString(Charset.forName("UTF-8"))
val responseType =
object : TypeReference<CommonResponse<CheckNicknameResponse>>() {}
val actualResult: CommonResponse<CheckNicknameResponse> = objectMapper.readValue(
responseContent,
responseType
)

// then
actualResult.data!!.isDuplicate shouldBe false
}

it("when nickname is used should throw DuplicateUserNicknameException") {
// given
val existedUserNickname = userRepository.findByEmail("test@gmail.com")?.nickname ?: ""

// when
val result = mockMvc.perform(
get("$baseUrl/check-nickname")
.param("nickname", existedUserNickname)
).also {
println(it.andReturn().response.contentAsString)
}
.andExpect(status().isBadRequest)
.andExpect(jsonPath("$.result").value("FAIL"))
.andReturn()

val responseContent = result.response.getContentAsString(Charset.forName("UTF-8"))
val responseType =
object : TypeReference<CommonResponse<CheckNicknameResponse>>() {}
val actualResult: CommonResponse<CheckNicknameResponse> = objectMapper.readValue(
responseContent,
responseType
)

// then
actualResult.message shouldBe "이미 존재 하는 닉네임 입니다."
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.restaurant.be.user.presentation.controller

import com.fasterxml.jackson.core.type.TypeReference
import com.fasterxml.jackson.databind.ObjectMapper
import com.fasterxml.jackson.databind.module.SimpleModule
import com.fasterxml.jackson.module.kotlin.KotlinModule
import com.restaurant.be.common.CustomDescribeSpec
import com.restaurant.be.common.IntegrationTest
import com.restaurant.be.common.PageDeserializer
import com.restaurant.be.common.response.CommonResponse
import com.restaurant.be.common.util.setUpUser
import com.restaurant.be.restaurant.presentation.controller.dto.common.RestaurantDto
import com.restaurant.be.user.repository.UserRepository
import io.kotest.matchers.shouldBe
import org.springframework.data.domain.Page
import org.springframework.test.web.servlet.MockMvc
import org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath
import org.springframework.test.web.servlet.result.MockMvcResultMatchers.status
import org.springframework.transaction.annotation.Transactional
import java.nio.charset.Charset

@IntegrationTest
@Transactional
class DeleteUserControllerTest(
private val mockMvc: MockMvc,
private val userRepository: UserRepository
) : CustomDescribeSpec() {
private val baseUrl = "/v1/users"
private val objectMapper: ObjectMapper = ObjectMapper().registerModule(KotlinModule()).apply {
val module = SimpleModule()
module.addDeserializer(Page::class.java, PageDeserializer(RestaurantDto::class.java))
this.registerModule(module)
}

init {
beforeEach {
setUpUser("test@gmail.com", userRepository)
}

describe("#deleteUser basic test") {
it("when user delete should return success") {
// given
// when
val result = mockMvc.perform(
delete("$baseUrl")
).also {
println(it.andReturn().response.contentAsString)
}
.andExpect(status().isOk)
.andExpect(jsonPath("$.result").value("SUCCESS"))
.andReturn()

val responseContent = result.response.getContentAsString(Charset.forName("UTF-8"))
val responseType =
object : TypeReference<CommonResponse<Void>>() {}
val actualResult: CommonResponse<Void> = objectMapper.readValue(
responseContent,
responseType
)

// then
actualResult.result shouldBe CommonResponse.Result.SUCCESS
}

it("when not exists user delete should return fail") {
// given
userRepository.deleteAll()

// when
val result = mockMvc.perform(
delete("$baseUrl")
).also {
println(it.andReturn().response.contentAsString)
}
.andExpect(status().isBadRequest)
.andExpect(jsonPath("$.result").value("FAIL"))
.andReturn()

val responseContent = result.response.getContentAsString(Charset.forName("UTF-8"))
val responseType =
object : TypeReference<CommonResponse<Void>>() {}
val actualResult: CommonResponse<Void> = objectMapper.readValue(
responseContent,
responseType
)

// then
actualResult.message shouldBe "존재 하지 않는 유저 입니다."
}
}
}
}
Loading

0 comments on commit cec9434

Please sign in to comment.