-
Notifications
You must be signed in to change notification settings - Fork 185
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
[1주차] 3단계 - 테스트를 통한 코드 보호 (5) #92
base: naheenosaur
Are you sure you want to change the base?
Conversation
} | ||
|
||
@Test | ||
@DisplayName("테이블 그룹은 2개 이상의 빈 테이블로 생성된다.") |
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.
테스트 코드 작성을 요구사항에 있는 항목 별 하나로 만들었는데,
그러다 보니 한 요구사항에 여러가지 조건이 같이 들어있는 경우가 있었습니다
이 요구사항 역시 2개 이상의 테이블 / 빈 테이블 이라는 두개의 요구사항으로 나누어 졌는데요,
그래서 한 테스트 코드에 두개의 검증이 생겼네요.
요구사항을 세밀하게 나눌 것인가, 테스트 코드를 나누어서 작성할 것인가 고민하다가
같은 내용에 대한 검증이라는 생각에 요구사항을 나누지 않고, 한 테스트 코드 안에 요구사항에 해당하는 검증을 모으는 것이 더 가독성이 있지 않을까 생각이 들어 이렇게 작성해봤습니다.
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.
일반적으로 테스트마다 하나의 논리적 개념을 테스트하는 것이 좋아요. 아래의 글이 도움 되면 좋겠어요.
https://softwareengineering.stackexchange.com/questions/7823/is-it-ok-to-have-multiple-asserts-in-a-single-unit-test
tableGroup = tableGroupBo.create(tableGroup); | ||
|
||
tableGroup.getOrderTables() | ||
.forEach(orderTable -> assertThat(orderTable.isEmpty()).isFalse()); |
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.
assert를 foreach 안에 사용했는데, assertAll처럼 함꼐 확인할 수 있는 좋은 방법이 없을까요..? 😢
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.
ObjectEnumerableAssert#allSatisfy(Consumer)
을 찾아보고 그 기능을 사용해 보면 어떨까요?
- Number -> PositiveNumber로 변경 - 객체내에서 멤버볌수 직접 접근
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.
테스트 코드를 잘 작성해 주셨습니다. 👍
질문에 대한 답변은 코멘트로 남겼어요.
그 외에도 몇 가지 의견을 남겨 놓았으니 충분히 고민하고 도전해 보세요!
진행 과정에서 궁금한 점은 댓글이나 Slack을 통해 물어보세요.
private static final Pattern NUMERIC_PATTERN = Pattern.compile("[+]?\\d+"); | ||
private int value; | ||
|
||
Number(List<String> strings) { | ||
PositiveNumber(List<String> strings) { |
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.
생성자 대신 정적 팩토리 메서드를 사용하면 어떨까요? 정적 팩토리 메서드는 이름만 잘 지으면 반환될 객체의 특성을 쉽게 묘사할 수 있어요. 아래의 글이 도움 되면 좋겠어요.
https://www.slipp.net/wiki/pages/viewpage.action?pageId=30771479
import java.util.List; | ||
import java.util.Optional; | ||
|
||
public interface DefaultMenuDao { |
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.
접두사 'Default'는 주로 구상 클래스(concrete class) 이름에 사용해요.
public interface DefaultMenuDao { | |
public interface MenuDao { |
@@ -16,7 +16,7 @@ | |||
import java.util.Optional; | |||
|
|||
@Repository | |||
public class MenuDao { | |||
public class MenuDao implements DefaultMenuDao { |
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.
클래스 이름은 JdbcTemplateMenuDao
가 적절해 보여요.
public class MenuDao implements DefaultMenuDao { | |
public class JdbcTemplateMenuDao implements DefaultMenuDao { |
@@ -70,7 +75,8 @@ public OrderTable save(final OrderTable entity) { | |||
return jdbcTemplate.query(sql, parameters, (resultSet, rowNumber) -> toEntity(resultSet)); | |||
} | |||
|
|||
private OrderTable select(final Long id) { | |||
@Override | |||
public OrderTable select(final Long 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.
OrderTableDao
외에 사용하는 곳이 없어 보이네요. public이 아닌 private으로 바꾸면 어떨까요?
@DisplayName("메뉴는 추가될 수 있다.") | ||
void createTest() { | ||
Menu menu = MenuTest.ofHalfAndHalf(); | ||
assertThat(menuBo.create(menu)); |
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.
더 많은 단언문이 필요해 보여요.
@DisplayName("모든 메뉴 리스트를 조회할 수 있다.") | ||
void readAllMenuListTest() { | ||
Menu menu = MenuTest.ofHalfAndHalf(); | ||
menuBo.create(menu); |
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.
menuBo.list()
를 테스트하기 위해서 menuBo.create(menu)
에 대한 테스트가 꼭 통과해야 할까요?
} | ||
|
||
@Test | ||
@DisplayName("테이블 그룹은 2개 이상의 빈 테이블로 생성된다.") |
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.
일반적으로 테스트마다 하나의 논리적 개념을 테스트하는 것이 좋아요. 아래의 글이 도움 되면 좋겠어요.
https://softwareengineering.stackexchange.com/questions/7823/is-it-ok-to-have-multiple-asserts-in-a-single-unit-test
tableGroup = tableGroupBo.create(tableGroup); | ||
|
||
tableGroup.getOrderTables() | ||
.forEach(orderTable -> assertThat(orderTable.isEmpty()).isFalse()); |
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.
ObjectEnumerableAssert#allSatisfy(Consumer)
을 찾아보고 그 기능을 사용해 보면 어떨까요?
|
||
import java.util.*; | ||
|
||
public class InMemoryMenuDao implements DefaultMenuDao { |
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.
가짜 객체 👍
- Class, Interface 이름 수정
- assertion 분리 - parameterizedTest 사용
- allSatisfy로 foreach 대체
- create에 대한 test에 속성값 확인
0a8fbea
to
b8c5830
Compare
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.
피드백을 잘 반영해 주셨습니다. 👍
추가로 고민해 보면 좋을 것 같은 의견을 남겨 놓았으니 충분히 고민하고 도전해 보세요!
진행 과정에서 궁금한 점은 댓글이나 Slack을 통해 물어보세요.
README.md
Outdated
- [ ] 메뉴는 0개 이상의 항목를 포함한다. | ||
- [X] 메뉴는 한 가지 메뉴그룹에 속해 있어야 한다. | ||
- [X] 메뉴의 가격은 0원 이상이다. | ||
- [X] 메뉴는 0개 이상의 항목를 포함한다. |
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.
오타 발견!
- [X] 메뉴는 0개 이상의 항목를 포함한다. | |
- [X] 메뉴는 0개 이상의 항목을 포함한다. |
Menu menuResult; | ||
assertThat(menuResult = menuBo.create(menu)); |
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.
아래의 코드로 개선해 보면 어떨까요?
Menu menuResult; | |
assertThat(menuResult = menuBo.create(menu)); | |
Menu menuResult = menuBo.create(menu); |
} | ||
|
||
@Test | ||
@DisplayName("메뉴는 0개 이상의 항목를 포함한다.") |
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.
오타 발견!
@DisplayName("메뉴는 0개 이상의 항목를 포함한다.") | |
@DisplayName("메뉴는 0개 이상의 항목을 포함한다.") |
Order order = OrderTest.ofOneHalfAndHalfInSingleTable(); | ||
order.setOrderStatus(OrderStatus.COMPLETION.toString()); | ||
|
||
assertThrows(IllegalArgumentException.class, | ||
() -> orderBo.changeOrderStatus(order.getId(), order)); |
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.
의도한 테스트와는 다른 테스트 코드입니다.
OrderTable orderTable = OrderTableTest.ofSingle(); | ||
orderTable = orderTableDao.save(orderTable); | ||
|
||
orderTable.setEmpty(true); | ||
tableBo.changeEmpty(orderTable.getId(), orderTable); | ||
|
||
assertThat(orderTable.isEmpty()).isTrue(); |
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.
의도한 테스트와는 다른 테스트 코드입니다.
tableGroup.setCreatedDate(LocalDateTime.now()); | ||
tableGroup.setId(EMPTY_TABLE_GROUP_ID); | ||
tableGroup.setOrderTables( | ||
Arrays.asList(OrderTableTest.ofEmpty(), OrderTableTest.ofAnotherEmpty()) |
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.
'단체 지정된 빈 테이블'은 실제로 존재할 수 있을까요?
안녕하세요. 김나희입니다.
3단계 테스트 코드 추가했습니다.
controller에 대한 테스트 코드에 대해서 한 가지 궁금한 것이 있는데
controller에 대한 테스트는
1번의 경우라면 역할 위임하는 단계에서 단순하게 역할을 위임하기 위해 포장한 메서드의 경우는 테스트 하지 않아도 된다고 들었던 기억이 있는데, 실제 서비스 기능에 대한 것을 테스트 하는 것 역시 동일하게 접근하면 하지 않아도 될 것 같아서요.
2번의 경우라면 controller에 대한 테스트는 get, post, put, delete에 대한 테스트만 되어도 되지 않을 까 생각을 했는데 controller 에 대한 테스트가 필요한 이유가 혹시 따로 있는지 궁급합니다.
감사합니다.