-
Notifications
You must be signed in to change notification settings - Fork 177
[Spring 지하철 노선도 - 1,2단계] 기론(김규철) 미션 제출합니다. #191
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
Conversation
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.
기론 안녕하세요! 이번 미션 리뷰를 맡은 소니입니다.
지하철 노선도 미션 잘 구현해주셨네요~
질문 주신 내용과 작업한 코드에 대해 몇가지 코멘트 남겼으니 확인 부탁드려요~🙂
|
||
private static final Long seq = 0L; | ||
private static final List<Station> stations = new ArrayList<>(); |
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.
1단계에서 2단계로 넘어가면서 불필요한 코드가 되었네요!
제거했습니다!
public class Station { | ||
private Long id; | ||
private String name; |
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.
불필요한 코드 제거했습니다!
|
||
@Override | ||
public boolean equals(Object o) { | ||
if (this == o) return true; | ||
if (o == null || getClass() != o.getClass()) return false; | ||
Line line = (Line) o; | ||
return Objects.equals(name, line.name); | ||
} | ||
|
||
@Override | ||
public int hashCode() { | ||
return Objects.hash(name); | ||
} | ||
} |
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.
동등성의 기준을 name으로 잡으셨군요. 그렇다면 id는 어떤 역할을 할까요?
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.
그 전에 1단계에서 dao 클래스에서 static List<Line> lines
와 같은 형태로 Line들을 저장하는 역할을 하는 상수가 있었습니다. 이 때, 들어오는 Line들마다 구별해주기 위해서 name을 기준으로 구별을 해주는데 이용했습니다.
그런데 현재는 db에 pk값으로 id를 자동으로 auto_increment 해주기 때문에 이를 통해서 식별할 수 있도록 되었습니다!
name은 unique이고 id는 pk이기 때문에 null을 허용하지 않는 id를 이용해서 식별하도록 하는 게 좋다고 생각합니다!
@RestController | ||
@RequestMapping("/lines") |
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.
@RequestMapping
사용 👍
private LineResponse() { | ||
} |
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.
LineAcceptanceTest
에 response.jsonPath()
메서드를 통해서 json형식을 다시 Object로 역직렬화를 하기 때문에 기본생성자가 없다면 역직렬화가 실패해서 인수테스트가 실패하므로 추가를 했습니다!
즉, 테스트에서 json으로 받은 값을 다시 객체로 변환해서 비교하기 위해서 추가했습니다!
Map<String, String> params = new HashMap<>(); | ||
params.put("name", "신분당선"); | ||
params.put("color", "bg-red-600"); |
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.
Map이 아닌 LineRequest를 사용하면 더 편리하지 않을까요?
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.
Map보다는 request이용이 더 편하네요! 수정했습니다
|
||
@DisplayName("전체 노선을 조회하면 200 ok와 노선 정보를 반환한다.") | ||
@Test | ||
void getLines() { | ||
Map<String, String> newBundangLine = new HashMap<>(); | ||
newBundangLine.put("name", "신분당선"); | ||
newBundangLine.put("color", "bg-red-600"); |
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.
body에 대한 값도 검증하면 좋지 않을까요?
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.
단순히 조회하는 로직이어서 조회한 id들만 잘 있는지 확인해도 충분하다고 생각했습니다. 왜냐하면 id가 잘 나온다면 같이 묶여있는 다른 데이터 또한 잘 올 것이라고 생각했기 때문입니다.
또한 조회하고 싶은 데이터가 변경 될 때마다 비교하는 코드가 추가되거나 삭제되므로 계속해서 테스트를 수정해야한다고 생각했습니다.
소니는 제 생각에 대해서 어떻게 생각하시나요?
다 적고 생각해보니 현재 테스트가 인수 테스트이기 때문에 요구사항에 맞는 body가 적절히 나왔는지도 검증하는게 맞다고 생각이 드네요..?
그렇다면 이러한 인수테스트에서는
또한 조회하고 싶은 데이터가 변경 될 때마다 비교하는 코드가 추가되거나 삭제되므로 계속해서 테스트를 수정해야한다고 생각했습니다.
이러한 이유때문에 잦은 수정이 발생할 것 같은데 어쩔수없는 부분일까요?
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.
아이디가 같으면 다른 데이터도 동일할 것이라는 것은 내부 구조를 이해한 개발자에게는 당연한거지만 일반 사용자에게는 당연하지 않을 수 있을 것 같아요.
오.. 정말 바로 와 닿게 되는 멘트네욤. 이해했습니다!
@Transactional | ||
@SpringBootTest | ||
public class LineRepositoryTest { | ||
|
||
@Autowired | ||
LineRepository lineRepository; |
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.
- Repository를 테스트하는데 SpringBootTest를 이용해 모든 Bean을 띄울 필요가 있을까요?
- 테스트에서 Transational 어노테이션은 어떤 역할을 하나요? 이 어노테이션을 없애면 어떻게 되나요?
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.
모든 빈을 끌고와서 저도 무겁다고 생각해서 @jdbcTest로 수정했습니다! @jdbcTest는 jdbc관련 빈만 끌고 오기 때문에 테스트 속도가 눈에 띄게 빨라졌습니다!
또한 @transactional로 테스트가 끝난 후, 롤백을 적용하려고 했는데 지금보니 JdbcTest안에 Trasanctional 어노테이션이 있었군요! 제거했습니다!
@Transactional | ||
@SpringBootTest | ||
public class LineServiceTest { | ||
|
||
@Autowired | ||
private LineService lineService; | ||
|
||
@Autowired | ||
private LineRepository lineRepository; | ||
|
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.
- Service 테스트도
@SpringBootTest
과@Transactional
을 사용하고 있네요 - 이 어노테이션 없이도 테스트 가능할까요?
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.
현재 레포지토리가 Fake 객체를 사용하지 않고 빈으로 등록된 repository를 이용하기 떄문에 의존성 주입을 하지 않으면 동작하지 않습니다. 또한 Junit에서는 jupiter가 빈을 관리하게되므로 스프링 빈을 사용하려면 @Autowired
를 명시하여 스프링 빈을 사용하겠다고 알려줘야한다고 알고 있습니다.
따라서 현재는 SpringBootTest에서 Jdbc관련 빈만 가져오는 JdbcTest로 수정했습니다!
|
||
public class LineUpdateDto { | ||
|
||
private final Long id; | ||
private final String name; | ||
private final String color; | ||
|
||
private LineUpdateDto(Long id, String name, String color) { | ||
this.id = id; | ||
this.name = name; | ||
this.color = color; | ||
} | ||
|
||
public static LineUpdateDto of(final Long id, final LineRequest lineRequest) { | ||
return new LineUpdateDto(id, lineRequest.getName(), lineRequest.getColor()); | ||
} |
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.
질문주신 부분에 대해 답변 드리자면, 저라면 LineUpdateDto를 따로 만들지는 않을 것 같습니다.
LineUpdateDto는 사실상 Line과 다른점이 없어서 LineRequest.toLine(id)
과 같은 메서드를 만들어 Line을 update의 인자로 넘길 것 같습니다.
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.
넵! 도메인으로 넘기면 됐겠네요..😂
지금은 save를 할때도 toLine이 있어서 오버로딩으로 toLine()
과 toLine(id)
를 만들까 했지만 막상 두개를 만들고 진행해보니 update메서드를 호출할때 toLine(id)
를 이용해야하는데 toLine()
을 이용하면서 헷갈리게 되더라구요!
그래서 그냥 toLine()
으로 통일하고 update(id, toLine()) 으로 수정하였습니다!
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.
기론 안녕하세요!
피드백 잘 반영해주셨네요! 구조도 이전보다 개선된게 느껴집니다. 수고하셨어요!💯
이번 단계는 여기서 머지하겠습니다.
다음 단계 진행해주세요~💪
@Transactional | ||
@SpringBootTest | ||
public class LineServiceTest { | ||
|
||
@Autowired | ||
private LineService lineService; | ||
|
||
@Autowired | ||
private LineRepository lineRepository; | ||
|
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.
@MockMvcTest?
@WebMvcTest?
class ServiceTest {
@MockBean
private Repository repository;
private Service service;
@BeforeEach
void setUp() {
service = new Service(repsitory)
}
}
안녕하세요 소니!
기론이라고 합니다!😁
이번 미션을 진행하면서 궁금한 점이 있었습니다.
update
메서드에서name과 color
를 받아서id
를 기준으로 업데이트를 해줍니다.그런데 여기서
update(id, name, color)
로 각각의 인자들을 받는 방식이 아닌,query를 날리는데 필요한 정보를 담는 dto
를 만들어서update(Dto dto)
로 dto안에 id, name, color를 담도록 해보았습니다. 이렇게클라이언트와 소통용 dto
가 아닌db와 소통용 dto
를 만드는 것에 대해서 소니의 생각이 궁금합니다!리뷰 잘 부탁드립니다🙂
감사합니다!