Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class ApiResponse<T> {
private final String status;
private final String message;
private final T data;
private String status;
private String message;
private T data;

public static <T> ApiResponse<T> success(String message, T data) {
return new ApiResponse<>("success", message, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,15 @@

import lombok.AllArgsConstructor;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@AllArgsConstructor
@NoArgsConstructor
public class CommonResponse<T> {
private final String status;
private final String message;
private final T data;
private String status;
private String message;
private T data;

public static <T> CommonResponse<T> success(String message, T data) {
return new CommonResponse<>("success", message, data);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,10 @@
import com.backend.server.api.common.dto.LoginUser;
import io.swagger.v3.oas.annotations.media.Schema;
import lombok.Getter;
import lombok.NoArgsConstructor;

@Getter
@NoArgsConstructor
public class MyInfoResponse {

@Schema(description = "사용자 이름", example = "홍길동")
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
package com.backend.server.api.common.auth.controller;

import static com.backend.server.fixture.UserFixture.MOCK_MVC_테스트시_로그인_계정;
import static com.backend.server.util.MockMvcUtil.convertToJson;
import static com.backend.server.util.MockMvcUtil.toDto;
import static com.backend.server.util.MockMvcUtil.toJsonPathDocument;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.backend.server.api.common.auth.dto.CommonSignInRequest;
import com.backend.server.api.common.dto.ApiResponse;
import com.backend.server.api.common.dto.LoginUser;
import com.backend.server.api.user.mypage.dto.MyInfoResponse;
import com.backend.server.config.MockMvcConfig;
import com.backend.server.model.entity.User;
import com.backend.server.model.repository.user.UserRepository;
import com.fasterxml.jackson.core.type.TypeReference;
import jakarta.servlet.http.Cookie;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.Import;
import org.springframework.http.MediaType;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;

@Transactional
@SpringBootTest
@AutoConfigureMockMvc
@Import(MockMvcConfig.class)
@DisplayName("CommonAuthController")
class CommonAuthControllerTest {

@Autowired private MockMvc mockMvc;
@Autowired private PasswordEncoder passwordEncoder;
@Autowired private UserRepository userRepository;

@Nested
class 로그인_API_는 {

@Test
void 사용가능한_엑세스_토큰을_응답한다() throws Exception {
/* 1. 로그인 */
//given
final User user = userRepository.save(MOCK_MVC_테스트시_로그인_계정.엔티티_생성(passwordEncoder, null));
userRepository.flush();
final CommonSignInRequest signInRequest = MOCK_MVC_테스트시_로그인_계정.로그인_요청_생성();

//when
final ResultActions resultActions = mockMvc.perform(post("/api/auth/sign-in")
.contentType(MediaType.APPLICATION_JSON)
.content(convertToJson(signInRequest)));

//then
resultActions.andExpect(status().isOk());

final Cookie refreshToken = resultActions.andReturn().getResponse().getCookie("refreshToken");
if (refreshToken == null)
throw new Exception("No refresh token found");
System.out.printf("refresh token : %s\n", refreshToken.getValue());

final String accessToken = toJsonPathDocument(resultActions).read("$.data.accessToken");
System.out.printf("access token : %s\n", accessToken);
/* 1. 로그인 */

/* 2. 발급 받은 엑세스 토큰으로 내 정보 조회하기 */
//given
final MyInfoResponse expectedMyInfoResponse = new MyInfoResponse(new LoginUser(user));

//when
final ResultActions resultActions2 = mockMvc.perform(get("/api/mypage")
.header("Referer", "http://localhost:3000")
.header("Authorization", "Bearer " + accessToken));

//then
resultActions2.andExpect(status().isOk());

final ApiResponse<MyInfoResponse> myInfoResponse = toDto(resultActions2, new TypeReference<>() {});
assertThat(myInfoResponse.getData())
.usingRecursiveComparison()
.isEqualTo(expectedMyInfoResponse)
.as("내 정보 조회 api 가 예상과 다른 값을 반환합니다.");
/* 2. 발급 받은 엑세스 토큰으로 내 정보 조회하기 */
}
}
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
package com.backend.server.api.common.s3.controller;

import static com.backend.server.util.MockMvcUtil.toJsonPathDocument;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;

import com.backend.server.config.ControllerTest;
import com.backend.server.util.S3ApiUtil;
import com.jayway.jsonpath.JsonPath;
import java.time.LocalDateTime;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
Expand Down Expand Up @@ -44,8 +44,7 @@ class Presigned_URL_API_는 {
//then
result.andExpect(status().isOk());

String responseJson = result.andReturn().getResponse().getContentAsString();
String presignedUrl = JsonPath.parse(responseJson).read("$.data", String.class);
String presignedUrl = toJsonPathDocument(result).read("$.data", String.class);
/* presigned url 을 발급받습니다. */

/* presigned url 로 파일이 잘 업로드 되는지 테스트 */
Expand Down
7 changes: 6 additions & 1 deletion src/test/java/com/backend/server/config/ControllerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,19 @@
import org.springframework.test.context.ActiveProfiles;
import org.springframework.test.context.TestExecutionListeners;

/**
* 로그인을 자동으로 해주어, 컨트롤러 레이어의 테스트를 쉽게 할수 있게 해주는 어노테이션입니다.<br>
* dev 서버용 인증필터를 사용합니다.<br>
* (엑세스 토큰이 없으면, 알아서 액세스 토큰을 만들어서 인증시켜줌)
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
@ActiveProfiles("dev")
@Import(MockMvcUTF8Config.class)
@Import(MockMvcConfig.class)
@TestExecutionListeners(
value = UserSaveListener.class,
mergeMode = TestExecutionListeners.MergeMode.MERGE_WITH_DEFAULTS)
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,7 @@
package com.backend.server.config;

import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity;

import org.springframework.boot.test.context.TestConfiguration;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Primary;
Expand All @@ -9,12 +11,13 @@
import org.springframework.web.filter.CharacterEncodingFilter;

@TestConfiguration
public class MockMvcUTF8Config {
public class MockMvcConfig {
@Bean
@Primary
public MockMvc customMockMvc(WebApplicationContext context) {
return MockMvcBuilders.webAppContextSetup(context)
.addFilter(new CharacterEncodingFilter("UTF-8", true))
.apply(springSecurity())
.build();
}
}
8 changes: 8 additions & 0 deletions src/test/java/com/backend/server/fixture/UserFixture.java
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
package com.backend.server.fixture;

import com.backend.server.api.admin.user.dto.AdminUserRequest;
import com.backend.server.api.common.auth.dto.CommonSignInRequest;
import com.backend.server.model.entity.Professor;
import com.backend.server.model.entity.User;
import com.backend.server.model.entity.enums.Gender;
Expand Down Expand Up @@ -130,4 +131,11 @@ public enum UserFixture {
.birthday(birthDate.format(DateTimeFormatter.ofPattern("yyyy-MM-dd")))
.build();
}

public CommonSignInRequest 로그인_요청_생성() {
final CommonSignInRequest commonSignInRequest = new CommonSignInRequest();
commonSignInRequest.setPassword(password);
commonSignInRequest.setStudentNumber(studentNumber);
return commonSignInRequest;
}
}
18 changes: 16 additions & 2 deletions src/test/java/com/backend/server/util/MockMvcUtil.java
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,16 @@
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;

import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.core.type.TypeReference;
import com.fasterxml.jackson.databind.JsonNode;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.SerializationFeature;
import com.fasterxml.jackson.datatype.jsr310.JavaTimeModule;
import com.jayway.jsonpath.DocumentContext;
import com.jayway.jsonpath.JsonPath;
import java.io.UnsupportedEncodingException;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.test.web.servlet.ResultMatcher;
import org.springframework.test.web.servlet.request.MockHttpServletRequestBuilder;
import org.springframework.util.LinkedMultiValueMap;
Expand All @@ -24,8 +28,8 @@ public class MockMvcUtil {
.disable(SerializationFeature.WRITE_DATES_AS_TIMESTAMPS);

/**
* 하나의 API 응답에 대해 여러번 이 함수를 호출할 일이 있다면, JsonPath 라이브러리로 대체하는걸 추천합니다.
* 이 메소드는 API 응답을 json 으로 파싱하므로, 한번의 API 응답에 대해 여러번 호출하기 부적절합니다.
* 이 메소드는 API 응답을 json 으로 파싱하므로, 한번의 API 응답에 대해 여러번 호출하기 부적절합니다.<br>
* 여러번 호출할거라면, toJsonPathDocument() / toDto 를 사용하세요.
*/
public static ResultMatcher jsonPathEquals(String jsonPath, Object expected) {
return result -> {
Expand Down Expand Up @@ -66,6 +70,16 @@ public static MultiValueMap<String, String> convertToParams(Object dto) {
return params;
}

public static DocumentContext toJsonPathDocument(ResultActions result) throws UnsupportedEncodingException {
String responseBody = result.andReturn().getResponse().getContentAsString();
return JsonPath.parse(responseBody);
}

public static <T> T toDto(ResultActions result, TypeReference<T> typeReference) throws Exception {
String responseBody = result.andReturn().getResponse().getContentAsString();
return mapper.readValue(responseBody, typeReference);
}

public static MockHttpServletRequestBuilder postJson(String url, Object body) throws JsonProcessingException {
return post(url)
.contentType(MediaType.APPLICATION_JSON)
Expand Down