Skip to content
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

Open
wants to merge 14 commits into
base: naheenosaur
Choose a base branch
from

Conversation

naheenosaur
Copy link

@naheenosaur naheenosaur commented Feb 19, 2020

안녕하세요. 김나희입니다.
3단계 테스트 코드 추가했습니다.

controller에 대한 테스트 코드에 대해서 한 가지 궁금한 것이 있는데
controller에 대한 테스트는

  1. 서비스 로직에서 정확한 결과가 리턴되는 것 까지를 테스트 하기 위함인지,
  2. 올바른 request로 200, 204와 같은 올바른 response 응답값이 나오는것에 대한 controller 의 기본 역할을 테스트 하기 위함인지 정확하게 알고 싶습니다.

1번의 경우라면 역할 위임하는 단계에서 단순하게 역할을 위임하기 위해 포장한 메서드의 경우는 테스트 하지 않아도 된다고 들었던 기억이 있는데, 실제 서비스 기능에 대한 것을 테스트 하는 것 역시 동일하게 접근하면 하지 않아도 될 것 같아서요.
2번의 경우라면 controller에 대한 테스트는 get, post, put, delete에 대한 테스트만 되어도 되지 않을 까 생각을 했는데 controller 에 대한 테스트가 필요한 이유가 혹시 따로 있는지 궁급합니다.
감사합니다.

}

@Test
@DisplayName("테이블 그룹은 2개 이상의 빈 테이블로 생성된다.")
Copy link
Author

Choose a reason for hiding this comment

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

테스트 코드 작성을 요구사항에 있는 항목 별 하나로 만들었는데,
그러다 보니 한 요구사항에 여러가지 조건이 같이 들어있는 경우가 있었습니다
이 요구사항 역시 2개 이상의 테이블 / 빈 테이블 이라는 두개의 요구사항으로 나누어 졌는데요,
그래서 한 테스트 코드에 두개의 검증이 생겼네요.

요구사항을 세밀하게 나눌 것인가, 테스트 코드를 나누어서 작성할 것인가 고민하다가
같은 내용에 대한 검증이라는 생각에 요구사항을 나누지 않고, 한 테스트 코드 안에 요구사항에 해당하는 검증을 모으는 것이 더 가독성이 있지 않을까 생각이 들어 이렇게 작성해봤습니다.

Copy link
Contributor

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());
Copy link
Author

Choose a reason for hiding this comment

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

assert를 foreach 안에 사용했는데, assertAll처럼 함꼐 확인할 수 있는 좋은 방법이 없을까요..? 😢

Copy link
Contributor

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로 변경
- 객체내에서 멤버볌수 직접 접근
Copy link
Contributor

@wotjd243 wotjd243 left a 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) {
Copy link
Contributor

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 {
Copy link
Contributor

Choose a reason for hiding this comment

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

접두사 'Default'는 주로 구상 클래스(concrete class) 이름에 사용해요.

Suggested change
public interface DefaultMenuDao {
public interface MenuDao {

@@ -16,7 +16,7 @@
import java.util.Optional;

@Repository
public class MenuDao {
public class MenuDao implements DefaultMenuDao {
Copy link
Contributor

Choose a reason for hiding this comment

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

클래스 이름은 JdbcTemplateMenuDao가 적절해 보여요.

Suggested change
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) {
Copy link
Contributor

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));
Copy link
Contributor

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);
Copy link
Contributor

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개 이상의 빈 테이블로 생성된다.")
Copy link
Contributor

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());
Copy link
Contributor

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 {
Copy link
Contributor

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에 속성값 확인
@naheenosaur naheenosaur changed the title [1주차] 3단계 - 테스트를 통한 코드 보호 (3) [1주차] 3단계 - 테스트를 통한 코드 보호 (4) Feb 25, 2020
Copy link
Contributor

@wotjd243 wotjd243 left a 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개 이상의 항목를 포함한다.
Copy link
Contributor

Choose a reason for hiding this comment

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

오타 발견!

Suggested change
- [X] 메뉴는 0개 이상의 항목를 포함한다.
- [X] 메뉴는 0개 이상의 항목을 포함한다.

Comment on lines 41 to 42
Menu menuResult;
assertThat(menuResult = menuBo.create(menu));
Copy link
Contributor

Choose a reason for hiding this comment

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

아래의 코드로 개선해 보면 어떨까요?

Suggested change
Menu menuResult;
assertThat(menuResult = menuBo.create(menu));
Menu menuResult = menuBo.create(menu);

}

@Test
@DisplayName("메뉴는 0개 이상의 항목를 포함한다.")
Copy link
Contributor

Choose a reason for hiding this comment

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

오타 발견!

Suggested change
@DisplayName("메뉴는 0개 이상의 항목를 포함한다.")
@DisplayName("메뉴는 0개 이상의 항목을 포함한다.")

Comment on lines 93 to 97
Order order = OrderTest.ofOneHalfAndHalfInSingleTable();
order.setOrderStatus(OrderStatus.COMPLETION.toString());

assertThrows(IllegalArgumentException.class,
() -> orderBo.changeOrderStatus(order.getId(), order));
Copy link
Contributor

Choose a reason for hiding this comment

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

의도한 테스트와는 다른 테스트 코드입니다.

Comment on lines 50 to 56
OrderTable orderTable = OrderTableTest.ofSingle();
orderTable = orderTableDao.save(orderTable);

orderTable.setEmpty(true);
tableBo.changeEmpty(orderTable.getId(), orderTable);

assertThat(orderTable.isEmpty()).isTrue();
Copy link
Contributor

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())
Copy link
Contributor

Choose a reason for hiding this comment

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

'단체 지정된 빈 테이블'은 실제로 존재할 수 있을까요?

@naheenosaur naheenosaur changed the title [1주차] 3단계 - 테스트를 통한 코드 보호 (4) [1주차] 3단계 - 테스트를 통한 코드 보호 (5) Mar 19, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants