Skip to content

[4기 홍혁준] Mission 1, 3 PR 제출합니다 #268

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

Open
wants to merge 19 commits into
base: HyuckJuneHong
Choose a base branch
from

Conversation

hongdosan
Copy link
Member

📌 과제 설명

고객(Member) 엔티티를 생성하고 그에 따른 CRUD 기능 테스트 구현했습니다.
고객, 주문, 상품 사이의 연관관계를 설정해보았습니다.

👩‍💻 요구 사항과 구현 내용

  • 자세한 명세서는 docs 파일에 있습니다.
  • Mission 1 : 고객(Member)의 CRUD를 구현한다.
  • Mission 3 : 연관관계를 설정해본다.

✅ PR 포인트 & 궁금한 점

현업에서의 mock Test에 대해 궁금합니다.
현업에서의 Controller Test에 대해 궁금합니다.

Copy link
Member

@Shin-Jae-Yoon Shin-Jae-Yoon left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혁준님 고생하셨습니다 ~! 사실 리뷰보단 질문의 장이 되어버린 것 같네요 ㅋ-ㅋ

@Configuration
@EnableJpaAuditing
public class JpaConfig {
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(질문) SpringbootJpaWeeklyMission에 @EnableJpaAuditing을 추가한 것이 아닌 따로 JpaConfig를 만드셨는데, 여기에는 어떤 설정들이 추가될 수 있나요 ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

QueryDSL 설정이 추후에 추가될 수 있다고 생각했습니다 ㅎㅎ


@Getter
public class DuplicateException extends RuntimeException {
private ErrorResult errorResult;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분과 this.errorResult 부분이 sonarLint에서 밑줄이 나왔던 것 같은데
반드시 필요한 부분인가요 !?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

나중에 ExceptionHandler 처리할 때, 꺼내서 확인해보는 상황이 필요할 때가 있었습니다!


@Getter
public class EntityNotFoundException extends RuntimeException {
private ErrorResult errorResult;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분도 마찬가지입니당

import org.springframework.http.HttpStatus;

@Getter
@AllArgsConstructor(access = AccessLevel.PRIVATE)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(질문) 이 부분은 @requiredargsconstructor가 아닌 @AllArgsConstructor(access = AccessLevel.PRIVATE)로 하신 이유가 있을까요 ??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이유가 있다기보다! Required를 해도 모든 필드에 대해 생성자가 생길테니, 크게 생각하지 않은 부분입니다!


return members.stream()
.map(MemberSimpleResponse::toDto)
.toList();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(복습) Stream.toList() vs Stream.collect(toList()) 에 대해서 복습 한번 하고 가면 좋을 것 같슴다 ~!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

한 번 더 공부하라고... 리뷰까지 남겨주시는.. 흑흑

public interface MemberRepository extends JpaRepository<Member, Long> {
Optional<Member> findByEmail(String email);

boolean existsByEmail(String email);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(복습) existsBy~ 의 쿼리가 어떤식으로 날라가는지 복습해보면 좋을 것 같슴다 ~!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

복습글 추천

@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class OrderItem {
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

현재 MySQL을 사용하는 상황인지 궁금함니다

private Address(String street, String detail) {
this.street = street;
this.detail = detail;
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

이 부분은 저도 헷갈리는데, 파라미터 개수가 3개보다 작은 경우 Builder를 쓰지 않는 것이 낫다고는 하던데
가독성, 통일성을 챙기는게 나을지, 위 규칙을 지킬지 생각해보면 좋을 것 같아용

Copy link
Member

@kmebin kmebin left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혁준님 과제하시느라 고생많으셨습니다! 굿굿

Comment on lines +21 to +23
@CreatedDate
@Column(name = "created_at", length = 20, nullable = false, updatable = false)
protected LocalDate createdAt;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LocalDate 타입에 length 조건을 추가한 이유가 있나요? 또 protected로 선언한 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

앗 length는 생각없이 넣었네요!
protected로 선언한 이유 : BaseTimeEntity는 상속해서 사용하기 때문에 protected로 선언해봤습니다!
희빈은 의견은 어떤가요??

Comment on lines +1 to +4
package kr.co.springbootjpaweeklymission.global.common;


import jakarta.persistence.Column;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

package와 import 사이 줄바꿈 1번 or 2번으로 컨벤션 통일하면 좋을 것 같아요!

Comment on lines +16 to +17
INVALID_PARAMETER("파라미터 값이 유효하지 않습니다.", HttpStatus.BAD_REQUEST),
;
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 이런식으로 쓰는게 새로운 값 추가할 때 더 좋을 것 같네요! 굿굿

Comment on lines +13 to +16
@Id
@GeneratedValue(strategy = GenerationType.IDENTITY)
@Column(name = "item_id", length = 4, nullable = false, unique = true)
private Long itemId;
Copy link
Member

@kmebin kmebin Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@Id가 충분히 pk로써 의미를 가지고 있고, 잘 통용되고 있다고 생각하는데 추가로 @Column 붙이는 이유는 더 명시적이고 통일성을 위함일까요?
추가로 여기서 Long 타입에 length 조건을 걸어준 이유가 있을까요?!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실상 name 속성만 있어도 될 것 같네요 ㅎㅎ
@column을 붙인 이유는 희빈님 말 그대로 더 명시적이고 통일성을 위함입니다!

Comment on lines +25 to +26
isEmail(putRequest.getEmail());
isCellPhone(putRequest.getCellPhone());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 네이밍만으로는 해당 이메일/번호의 중복을 체크하는 메서드인지 파악하기 어려운 것 같습니다

Comment on lines +21 to +22
@PostMapping
public ResponseEntity<Long> createMember(@RequestBody @Validated MemberPutRequest putRequest) {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드 파라미터 검증에 @Valid가 아닌 @Validated를 사용하신 이유가 있을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

예전이 스터디 했던 팀원분이 @validated가 더 좋다. 라는 말을 들었어서 사용했는데, 지금 다시 찾아보니, 딱히 좋은 점을 찾지 못하겠네요.
무작정 말만 듣고 적용했던 과거의 나에게 반성문을 쓰도록 하겠습니다 ㅠ

Comment on lines +52 to +53
assertThat(actual.getModifiedAt()).isEqualTo(LocalDate.now());
}
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

modifiedAt과 LocalDate.now()이 시간적 차이가 발생하는 경우는 없을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

LocalDateTime이 아닌 LocalDate이기 때문에, 괜찮다고 생각했습니다!
근데 만약 23시 59분에 테스트를 돌렸다면..? 이점을 고려해봐야겠네요 ㅠ

Comment on lines +107 to +108
@Test
@CsvSource(value = {"", "[email protected]", "[email protected]"})
Copy link
Member

@kmebin kmebin Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@CsvSource는 사용하지 않고 있는 것 같습니다!~

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

import static org.assertj.core.api.Assertions.assertThatThrownBy;

@DataJpaTest
@DisplayNameGeneration(DisplayNameGenerator.ReplaceUnderscores.class)
Copy link
Member

@kmebin kmebin Jul 27, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

메서드에 @DisplayName을 적용하면 불필요한 부분이라고 생각하는데, 추가하신 이유가 있으실까요?!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

실수입니다!

Comment on lines +52 to +53
assertThat(savedMember.getAddress().getStreet()).isEqualTo(member.getAddress().getStreet());
assertThat(savedMember.getAddress().getDetail()).isEqualTo(member.getAddress().getDetail());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Member 엔티티에 getStreet, getDetail 메서드를 구현하신걸로 기억합니다.!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

아맞다 ㅋㅋ

Copy link

@parksey parksey left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

혁준님 작성하시느라 고생하셨습니다!
이런 사소한 것 까지 꼼꼼히 하시는 모습 너무 보기 좋은 거 같습니다.

리뷰는 공통된 부분은 빼고 나머지 부분만 질문 드렸습니다.

코드 잘 봤어요!


@Slf4j
@RestControllerAdvice
public class NotValidExceptionHandler {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저도 유사하게 exceptionhandler를 사용했었는데 하나의 클래스에서 한 것이 아닌 여러 클래스로 나눠서 처리한 이유가 궁금합니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

사실 한 프로젝트당 하나의 ControllerAdvice만 관리하는 것이 좋은데, 객체를 분리하는게 습관이 되어서 고쳐보도록 하겠습니다 ㅠ

import static org.mockito.BDDMockito.given;

@ExtendWith(MockitoExtension.class)
class MemberServiceUnitTest {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

UnitTest와 단위테스트를 나눈 기준과 이유가 어떤건가요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

mock을 너무 많이 사용하게 되는 부분은 통합으로 빼서 테스트를 돌렸습니다 ㅎㅎ

@Entity
@Table(name = "tbl_orders")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order {
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Order와 OrderItem은 어떤 기준으로 패키지를 분리하셨나요?
패키지 전체가 엔티티기준으로 분리된 건가요? 아님 도메인으로 분리하신건가요??

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

저는 둘다입니다. 처음에는 도메인 기준으로 분리를 했지만, orderItem을 어디에서 관리하는게 좋을 지 고민하다가, 도저히 고를 수가 없어서 따로 뺐습니다! 추후에 개발을 더 진행한다면 또 변경될 수 있는 부분이라고 생각합니다 ㅎ

Copy link

@ymkim97 ymkim97 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

과제 하느라 고생하셨습니다!!!
조금 늦게 달아서 다른 분들과 겹치거나 이미 잘 해주셔서 많지 않습니다 ㅠ.ㅠ

runtimeOnly 'com.h2database:h2'

//MySQL
runtimeOnly 'com.mysql:mysql-connector-j'
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Dependency를 이렇게 나누니까 정말 좋은거 같아요! 배워갑니다 >.<

@@ -0,0 +1,17 @@
package kr.co.springbootjpaweeklymission.item.domain.entity;

import jakarta.persistence.*;
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

와일드 카드 import는 가급적 쓰지 않는 것이 좋다고 합니다!
아마 인텔리제이가 자동으로 이렇게 만들어줬을거고 저도 순간 잊어서 이렇게 했지만🥺...
세팅에서 예방할 수 있습니다!

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오홍 넵~

@Table(name = "tbl_orders")
@NoArgsConstructor(access = AccessLevel.PROTECTED)
public class Order {
@Id
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

오 저도 Order와 OrderItem은 어떤 기준으로 패키지를 분리하셨는지 궁금합니다!
코드를 작성하면서 궁금했는데 Order, OderItem, Item과 같은 연관관계가 있으면 어떻게 패키지를 분리하는 것이 좋을까요?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

OrderItem 은 사실 어느 곳에 들어가도 상관없을 것 같습니다! 하지만 저 같은 경우엔 둘 중 어디에 넣을 지 계속 고민하다가 분리를 했는데, 추후에 변경될 수도 있는 부분입니다 ㅎ 만약 넣는다면 책임이 더 많은 order 패키지에 넣을 것 같네요 ㅎ

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

5 participants