test: AuthControllerTest 코틀린 전환 및 일부 테스트 추가

This commit is contained in:
이상진 2025-07-13 20:53:18 +09:00
parent 17de8e9709
commit 8fdd4c4a03

View File

@ -1,118 +1,139 @@
package roomescape.system.auth.web; package roomescape.system.auth.web
import static org.assertj.core.api.Assertions.*; import io.mockk.every
import static org.hamcrest.Matchers.*; import org.hamcrest.Matchers.containsString
import org.hamcrest.Matchers.`is`
import org.springframework.data.repository.findByIdOrNull
import roomescape.common.MemberFixture
import roomescape.common.RoomescapeApiTest
import roomescape.system.exception.ErrorType
import java.util.Map; class AuthControllerTest : RoomescapeApiTest() {
import org.junit.jupiter.api.DisplayName; val userRequest: LoginRequest = MemberFixture.userLoginRequest()
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.test.context.jdbc.Sql;
import io.restassured.RestAssured; init {
import io.restassured.http.ContentType; Given("로그인 요청을 보낼 때") {
import roomescape.member.infrastructure.persistence.Member; val endpoint: String = "/login"
import roomescape.member.infrastructure.persistence.MemberRepository;
import roomescape.member.infrastructure.persistence.Role;
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) When("로그인에 성공하면") {
@Sql(scripts = "/truncate.sql", executionPhase = Sql.ExecutionPhase.BEFORE_TEST_METHOD) val expectedToken: String = "expectedToken"
class AuthControllerTest {
@Autowired every {
private MemberRepository memberRepository; memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
} returns user
@LocalServerPort every {
private int port; jwtHandler.createToken(user.id!!)
} returns expectedToken
@Test Then("토큰을 쿠키에 담아 응답한다") {
@DisplayName("로그인에 성공하면 JWT accessToken을 응답 받는다.") runPostTest(endpoint, body = MemberFixture.userLoginRequest()) {
void getJwtAccessTokenWhenlogin() { statusCode(200)
// given cookie("accessToken", expectedToken)
String email = "test@email.com"; header("Set-Cookie", containsString("Max-Age=1800000"))
String password = "12341234"; header("Set-Cookie", containsString("HttpOnly"))
memberRepository.save(new Member(null, "이름", email, password, Role.MEMBER)); header("Set-Cookie", containsString("Secure"))
}
Map<String, String> loginParams = Map.of( }
"email", email, }
"password", password
); When("회원을 찾지 못하면") {
every {
// when memberRepository.findByEmailAndPassword(userRequest.email, userRequest.password)
Map<String, String> cookies = RestAssured.given().log().all() } returns null
.contentType(ContentType.JSON)
.port(port) Then("400 에러를 응답한다") {
.body(loginParams) runPostTest(endpoint, body = userRequest) {
.when().post("/login") log().all()
.then().log().all().extract().cookies(); statusCode(400)
body("errorType", `is`(ErrorType.MEMBER_NOT_FOUND.name))
// then }
assertThat(cookies.get("accessToken")).isNotNull(); }
} }
@Test When("잘못된 요청을 보내면 400 에러를 응답한다.") {
@DisplayName("로그인 검증 시, 회원의 name을 응답 받는다.")
void checkLogin() { Then("이메일 형식이 잘못된 경우") {
// given val invalidRequest: LoginRequest = userRequest.copy(email = "invalid")
String email = "test@test.com";
String password = "12341234"; runPostTest(endpoint, body = invalidRequest) {
String accessTokenCookie = getAccessTokenCookieByLogin(email, password); log().all()
statusCode(400)
// when & then body("message", `is`("이메일 형식이 일치하지 않습니다. 예시: abc123@gmail.com"))
RestAssured.given().log().all() }
.contentType(ContentType.JSON) }
.port(port)
.header("cookie", accessTokenCookie) Then("비밀번호가 공백인 경우") {
.when().get("/login/check") val invalidRequest = userRequest.copy(password = " ")
.then()
.body("data.name", is("이름")); runPostTest(endpoint, body = invalidRequest) {
} log().all()
statusCode(400)
@Test body("message", `is`("비밀번호는 공백일 수 없습니다."))
@DisplayName("로그인 없이 검증요청을 보내면 401 Unauthorized 를 응답한다.") }
void checkLoginFailByNotAuthorized() { }
RestAssured.given().log().all() }
.contentType(ContentType.JSON) }
.port(port)
.when().get("/login/check") Given("로그인 상태를 확인할 때") {
.then() val endpoint: String = "/login/check"
.statusCode(401);
} When("로그인된 회원의 ID로 요청하면") {
every { jwtHandler.getMemberIdFromToken(any()) } returns user.id!!
@Test every { memberRepository.findByIdOrNull(user.id!!) } returns user
@DisplayName("로그아웃 요청 시, accessToken 쿠키가 삭제된다.")
void checkLogout() { Then("회원의 이름을 응답한다") {
// given runGetTest(endpoint) {
String accessToken = getAccessTokenCookieByLogin("email@email.com", "password"); statusCode(200)
body("data.name", `is`(user.name))
// when & then }
RestAssured.given().log().all() }
.port(port) }
.header("cookie", accessToken)
.when().post("/logout") When("토큰은 있지만 회원을 찾을 수 없으면") {
.then() val invalidMemberId: Long = -1L
.statusCode(200)
.cookie("accessToken", ""); every { jwtHandler.getMemberIdFromToken(any()) } returns invalidMemberId
} every { memberRepository.findByIdOrNull(invalidMemberId) } returns null
private String getAccessTokenCookieByLogin(final String email, final String password) { Then("400 에러를 응답한다.") {
memberRepository.save(new Member(null, "이름", email, password, Role.ADMIN)); runGetTest(endpoint) {
statusCode(400)
Map<String, String> loginParams = Map.of( body("errorType", `is`(ErrorType.MEMBER_NOT_FOUND.name))
"email", email, }
"password", password }
); }
}
String accessToken = RestAssured.given().log().all()
.contentType(ContentType.JSON) Given("로그아웃 요청을 보낼 때") {
.port(port) val endpoint: String = "/logout"
.body(loginParams)
.when().post("/login") When("로그인 상태가 아니라면") {
.then().log().all().extract().cookie("accessToken"); setUpNotLoggedIn()
return "accessToken=" + accessToken; Then("로그인 페이지로 이동한다.") {
runPostTest(endpoint) {
log().all()
statusCode(302)
header("Location", containsString("/login"))
}
}
}
When("로그인 상태라면") {
setUpUser()
every { memberRepository.findByIdOrNull(user.id!!) } returns user
Then("토큰의 존재 여부와 무관하게 토큰을 만료시킨다.") {
runPostTest(endpoint) {
log().all()
statusCode(200)
cookie("accessToken", "")
header("Set-Cookie", containsString("Max-Age=0"))
}
}
}
}
} }
} }