-
Notifications
You must be signed in to change notification settings - Fork 0
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[#3]컨트롤러 생성 및 통합테스트 코드작성 #4
Conversation
seunghaen
commented
Dec 9, 2024
•
edited
Loading
edited
- main 메서드 패키지 변경
- 롬복 dependency 추가
- DTO 클래스 작성
- Menu Controller
- Order Controller
- Payment Controller
- Menu 통합테스트
- Order 통합테스트
- Payment 통합테스트
- 매장별 관리를 위한 카테고르 Controller / 통합테스트 추가
- 있어서는 안되는 필드 검증하기
application/build.gradle
Outdated
@@ -16,6 +16,9 @@ repositories { | |||
|
|||
dependencies { | |||
implementation 'org.springframework.boot:spring-boot-starter-web' | |||
implementation 'org.projectlombok:lombok:1.18.28' |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Exception들이 불리는 위치에 따라서 여기서 처리할 지, 각각의 컨트롤러에서 처리할지 고민해 보시면 좋을 것 같아요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
현재는 모든 컨트롤러에서 공통적으로 Throw할 수 exception들에 대해서 GlobalExceptionHandler에서 처리하고 있습니다.
-
각 컨트롤러별 Exception은 현재 상세로 정의되지 않았으나 특정 컨트롤러나 서비스에서 throw하는 Exception은 각 컨트롤러에서 핸들링 할 예정입니다.
현재는 특정 컨트롤러에서 발생하는 Custom Exception을 정의하지 않았지만 서비스 코드를 작성해 나가면서 해당 부분에 대해서 정의하고 처리하는 것으로 소스를 발전시킬 계획입니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
상수값들을 enum으로 관리하는 것과 DB에서 관리하는 것의 장단점에 대해서
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
enum의 항목이 늘어나면, 배포를 새로해야 합니다. :-)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
매장별 API를 발전시키기 위해 카테고리의 경우 별도 데이터로서 관리할 예정이고 현재 정의한 ENUM은 비즈니스 적으로 잦은 변경/배포가 불필여한 영역이라 공통코드와 같이 DB에서 처리하지 않고 ENUM으로서 관리할 예정입니다.
@RestController | ||
@RequestMapping("/menus") | ||
@AllArgsConstructor | ||
public class MenuController { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
추가로 몇 개의 API를 추가하면, 여러 매장을 커버할 수 있을 것 같아요.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
category를 관리하는 API를 추가하였습니다.
storeId와 같은 값은 기존 커밋했던 DTO를 수정하여 추가하며 Request Body나 Path에서 받지 않고 세션으로 처리하는 방향으로 구상중입니다.
@Setter | ||
@AllArgsConstructor | ||
@NoArgsConstructor | ||
@Builder |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
각각의 어노테이션의 의도에 대해서 얘기해보도록 하죠.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
-
Getter
객체를 JSON으로 변환하는 과정에서 필요합니다.
Jackson 라이브러리는 객체를 JSON으로 변환할 때, 기본적으로 클래스의 Getter 메서드를 호출하여 값을 가져옵니다. -
NoArgsConstructor
JSON을 객체로 변환하는 과정에서 필요합니다.
Jackson 라이브러리는 기본생성자를 통해 객체를 생성하고 필드값을 주입하기 때문에 기본생성자를 정의해줄 필요가 있습니다. -
Setter
해당 어노테이션은 삭제했습니다. DTO를 생성 후, 해당 DTO 내부의 값을 수정하는 코드가 현재는 필요하지 않고, 조심할 필요가 있다고 생각하여 수정했습니다.
Jackson 라이브러리는 Setter를 통해 기본 객체에 필드값이 주입하는 것이 아니라 플렉션을 통해 필드에 값을 직접 설정하기때문에 객체를 생성하는 과정에서도 헤당 어노테이션은 필요가 없다고 판단했습니다. -
Builder
라이브러리 등에서 필수적인 코드가 아니라, DTO생성에 유연성과 가독성을 위해 추가하였습니다.
builder메서드, DTOBuild클래스, build메서드를 생성하여 DTO인스터를 new 키워드를 이용하여 생성자를 통해서 생성하는 것이 아니라, build패턴을 통해서 생성할 수 있도록 합니다.
테스트 등에서 DTO를 생성할때 좀 더 가독성있고, 유연하게 객체를 생성할 수 있게됩니다.
(PaymentReqDTO에서는 상속관계를 이용한 DTO가 있는데 이때는 SuperBuilder 어노테이션 사용)
*/ | ||
@GetMapping | ||
public ResponseEntity<ApiResDTO<List<MenuResDTO>>> getAllMenus(@RequestParam(required = false) MenuCategory category) { | ||
List<MenuResDTO> menus = menuService.getAllMenus(category); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
서비스에서 DTO를 리턴하는 것에 대해서
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
현재 해당 PR에서는 서비스를 직접 이용하는 코드는 없으나 서비스 코드 작성시에는 Entity를 반환하려고 합니다.
비즈니스 로직을 담당하는 Service계층에서 Resonse에 해당하는 DTO를 직접반환하는 것은 View에 종속되게 되어 Spring을 이용하여 MVC설계를 하는 해당 프로젝트에는 맞지 않다고 생각합니다.(DTO가 변경되면 service가 함께 거기에 종속되어 변경되어야 하기 때문에)
하나의 비즈니스 로직에서 조금씩만 다른 형태의 DTO를 return 해야하는 경우에도 서로다른 서비스 메서드를 생성해야 하는 등 코드가 중복으로 작성되는 사례 등도 발생할 수 있다고 생각합니다.
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; | ||
|
||
|
||
@WebMvcTest(MenuController.class) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
@SpringBootTest(..........)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
스프링 위에 올라간 컨트롤러의 통합테스트의 의도에 맞게 해당 어노테이션으로 수정하였습니다.
mockMvc.perform(get("/menus/1") | ||
.contentType(MediaType.APPLICATION_JSON)) | ||
.andExpect(status().isOk()) | ||
.andExpect(jsonPath("$.data.id").value(1L)) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
있어서는 안되는 필드가 있는지 없는지는 어떻게 검증할 수 있을까요?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
JSON String의 Response를 Map으로 파싱하여 생성한 keySetList와, DTO의 필드를 List화 하여 이를 비교하는 테스트 코드를 작성하여 추가했습니다.
JSON을 Map으로 파싱하는 과정은 jackson라이브러리를 이용하였고,
Class필드는 Java Reflection API를 사용하여 필드 이름을 동적으로 생성하도록 코드를 작성하였습니다.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
최근 변경사항만 마지막으로 확인하였는데, 좋은 것 같습니다!!