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

TemplateServiceTest 추가 #661

Merged
merged 7 commits into from
Sep 20, 2024
Merged

TemplateServiceTest 추가 #661

merged 7 commits into from
Sep 20, 2024

Conversation

HoeSeong123
Copy link
Contributor

@HoeSeong123 HoeSeong123 commented Sep 18, 2024

⚡️ 관련 이슈

close #645

📍주요 변경 사항

TemplateService 테스트 작성

🎸기타

테스트 실패 문제

켬미와 동일하게 flyway 설정 때문에 테스트 코드가 자꾸 실패하는 문제가 발생했었습니다.
이에 테스트 코드에서 사용하는 application-db.yml에 다음과 같은 설정을 추가해주었습니다.

flyway:
  enabled: false

중복되는 테스트 코드

  • TemplateService의 경우 아래 코드와 같이 TemplateRepository의 반환값을 그대로 리턴하는 메소드들이 몇 개 있습니다.
public Template getById(Long id) {
    return templateRepository.fetchById(id);
}

public List<Template> getByMemberId(Long memberId) {
    return templateRepository.findByMemberId(memberId);
}

public Page<Template> findAll(
        Long memberId, String keyword, Long categoryId, List<Long> tagIds, Pageable pageable
) {
    return templateRepository.findAll(
            new TemplateSpecification(memberId, keyword, categoryId, tagIds), pageable);
}
  • 이런 경우 RepositoryTest와 중복되는 테스트들이 몇 개 생겨나는데 이런 경우에도 ServiceTest를 작성해야 하는지 의문입니다.
    • 우선 저는 중복되더라도 테스트 코드를 작성하였습니다.
    • 테스트 코드는 해당 클래스의 명세서와도 같고, 테스트 코드를 봤을 때 해당 클래스를 어떻게 사용하는거구나, 어떤 에러가 발생할 수 있구나 등을 알 수 있게 하는 것이 목적이라고 생각하기 때문입니다.
    • 다른 분들의 의견이 궁금합니다.

지연 로딩 문제

  • [REFACTOR] Service Layer 리팩토링 #650 (comment)
  • 저도 마찬가지로 짱수와 동일한 프록시 객체 접근 문제가 발생합니다.
  • 몰리와 동일하게 @Transactional 어노테이션을 통해 트랜잭션을 생성하는 방식으로 처리했는데, 우선은 프로덕션 코드는 수정되면 안 될 것 같아서 테스트 코드에 @Transactional을 추가하는 식으로 해결하였습니다.
  • 추후에 해당 어노테이션을 지우고, 프로덕션 코드에 적용하는 식으로 변경해야 할 것 같습니다.

기타 리팩토링 사항

@HoeSeong123 HoeSeong123 added refactor 요구사항이 바뀌지 않은 변경사항 BE 백엔드 labels Sep 18, 2024
@HoeSeong123 HoeSeong123 added this to the 5차 스프린트🍗 milestone Sep 18, 2024
@HoeSeong123 HoeSeong123 self-assigned this Sep 18, 2024
Copy link
Contributor

@kyum-q kyum-q 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 84 to 88
assertAll(
() -> assertThat(actual.getTitle()).isEqualTo(templateRequest.title()),
() -> assertThat(actual.getMember()).isEqualTo(member),
() -> assertThat(actual.getCategory()).isEqualTo(category)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

description이랑 소스코드, 썸네일 순서, 태그도 확인하면 좋을 것 같아요 !

Copy link
Contributor

Choose a reason for hiding this comment

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

추가적으로 service에서 반환하는 객체만 비교하고, 데이터베이스에 실제로 추가되었는지 체크 안해도 될까요?

레포지토리 테스트가 아니라서 정답은 못찾겠지만, 저는 실제 데이터베이스에 추가되었는지 체크하는 로직이 있으면 더 좋을 것 같아요 ! (제 코드도 한번 더 확인해봐야겠네요..)

이에 대해 초롱과 다른 사람들은 어떻게 생각하는지 궁금합니다 !

Copy link
Contributor

Choose a reason for hiding this comment

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

Repository 테스트를 항상 잘 작성한다면 굳이 체크를 할 필요가 없을 것 같기는 합니다만....
저도 고민이 되네요.
서비스 계층의 특별한 역할이 존재하는 것이 아니라, 거의 Repository 메서드로 포워딩 하는 느낌이라서 무엇을 테스트 해야 하나 하는 고민도 들고요.

저는 데이터베이스에 추가되는지 확인하는 로직은 있으면 좋고, 없어도 그만~ 의 느낌인 것 같네요!

Copy link
Contributor

Choose a reason for hiding this comment

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

저는 findAll 메서드의 결과만 놓고 검증해야 한다고 생각합니다.

구체적인 로직을 몰라도 테스트를 할 수 있어야 한다고 생각하기 때문입니다.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저도 제우스 의견에 동의합니다.
해당 메소드에 대한 테스트는 어떤 입력을 했을 때 이런 출력이 나와를 테스트하는 거지, 내부의 로직이 전부 정상적으로 동작하는지를 확인하는 것은 아니라고 생각합니다.

Copy link
Contributor Author

@HoeSeong123 HoeSeong123 Sep 20, 2024

Choose a reason for hiding this comment

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

description이랑 소스코드, 썸네일 순서, 태그도 확인하면 좋을 것 같아요 !

썸네일 순서와 태그는 Template이 가지고 있는 필드가 아니어서 검사 로직에서 제외했습니다.
sourceCode의 경우는 양방향으로 연결되어 있어 sourceCode가 저장되어 있지 않으면 값이 들어오지 않습니다. 따라서 제외했습니다.
description은 추가하였습니다.

Copy link
Contributor

@jminkkk jminkkk left a comment

Choose a reason for hiding this comment

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

안녕하세요 초롱~
수고하셨습니다 🔥
확인 부탁드려요 ㅎㅎ

CreateTemplateRequest createdTemplate = makeTemplateRequest("title");
saveTemplate(createdTemplate, new Category("category1", member), member);
@Test
@DisplayName("멤버 ID로 템플릿 조회 성공: 해당하는 템플릿이 없는 경우")
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("멤버 ID로 템플릿 조회 성공: 해당하는 템플릿이 없는 경우")
@DisplayName("멤버 ID로 템플릿 조회 성공: 해당하는 템플릿이 없는 경우 빈 목록을 반환")

Comment on lines +156 to +157
@DisplayName("검색 기능")
class FindAll {
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("검색 기능")
class FindAll {
@DisplayName("템플릿 목록 조회")
class FindAll {

Copy link
Contributor Author

Choose a reason for hiding this comment

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

몰리가 작성했던 테스트들을 그대로 가져왔던 것들인데 검색 기능이 더 명확하지 않나요?
템플릿 목록 조회도 하기는 하지만, 옵션에 따라 다르게 반환하는데 단순히 템플릿 목록 조회라고 하면 명확하지 못 한 것 같습니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

맞아요~ 요청드린 것 중에 여러개가 제가 작성한 것도 알고 있어요
그래서 제가 더 정정해야겠다고 생각했어요


저는 템플릿을 조회하는 기능 중에 키워드 검색이 있는 것 같다고 생각을 했었어요.
또 검색 보다는 조회가 더 큰 범위라고 생각해서 정정 부탁드렸습니답...

마이페이지에서 내 글만 조회를 하거나, 필터링이 전혀 없이 단순 GET /templates 을 한다고 생각을 했을 때 오히려 조회가 더 명확할 것 같아서요. 그런데 사람마다 다르게 느껴질 수도 있겠네요 🤔

제 의견에 대한 설명이 없어서 의도와 다르게 전달된 것 같아서 의견 전달만 명확하게 드려봅니다~ 🔥

private Template template1, template2, template3;

@Test
@DisplayName("검색 기능: 회원 ID로 템플릿 조회 성공")
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("검색 기능: 회원 ID로 템플릿 조회 성공")
@DisplayName("템플릿 목록 조회 성공: 특정 회원의 템플릿 목록 조회")

Comment on lines +169 to +174
String keyword = null;
Long categoryId = null;
List<Long> tagIds = null;
Pageable pageable = PageRequest.of(0, 10);

Page<Template> actual = sut.findAll(memberId, keyword, categoryId, tagIds, pageable);
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
String keyword = null;
Long categoryId = null;
List<Long> tagIds = null;
Pageable pageable = PageRequest.of(0, 10);
Page<Template> actual = sut.findAll(memberId, keyword, categoryId, tagIds, pageable);
Pageable pageable = PageRequest.of(0, 10);
Page<Template> actual = sut.findAll(memberId, null, null, null, pageable);

(다른 메서드도 포함) 변수 할당을 안해도 의미가 충분히 보일 것 같아요!

Copy link
Contributor Author

Choose a reason for hiding this comment

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

저는 조금 반대입니다. 다른 테스트들도 같이 본다면 변수 할당을 하지 않아도 어떤 변수들에 null이 들어간건지 바로 알 수 있지만, 해당 테스트 코드만을 봤을 때는 알기 힘들다고 생각해요

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 +240 to +242
.containsExactlyInAnyOrder(
templateRepository.fetchById(1L),
templateRepository.fetchById(2L)),
Copy link
Contributor

Choose a reason for hiding this comment

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

이것도 취향 차이지만...
한줄로 적어도 좋을 것 같아요!
위의 allMatch보다 길이가 짧아서 가능할 것 같은...??

Suggested change
.containsExactlyInAnyOrder(
templateRepository.fetchById(1L),
templateRepository.fetchById(2L)),
.containsExactlyInAnyOrder(templateRepository.fetchById(1L),templateRepository.fetchById(2L)),

Copy link
Contributor Author

Choose a reason for hiding this comment

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

이거...한 줄로 쓰면 자동으로 줄바꿈 됩니다..😭

Comment on lines 284 to 287
template.getMember().getId().equals(member1.getId())
&& (template.getTitle().contains(keyword) || template.getDescription()
.contains(keyword)))
);
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
template.getMember().getId().equals(member1.getId())
&& (template.getTitle().contains(keyword) || template.getDescription()
.contains(keyword)))
);
template.getMember().getId().equals(member1.getId())
&& (template.getTitle().contains(keyword)
|| template.getDescription().contains(keyword)))
);

으엥 이렇게 보니까 이상한 것 같긴 한데 .. 암튼 요런 느낌.. 어떨까요?
image

Copy link
Contributor

Choose a reason for hiding this comment

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

저도 몰리 의견에 한 표 추가합니다!

6.4. 줄바꿈 허용 위치
네이버 핵데이 컨벤션인데요. 여기서도 연산자 앞에서 줄바꿈을 규칙으로 지정하고 있어요.

조건 연산자로 연결된 줄이 길어질 경우, 조건 연산자 앞에서 개행을 해주면 훨씬 가독성이 좋아지는 것 같네용

Copy link
Contributor Author

Choose a reason for hiding this comment

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

해당 테스트 코드들을 TemplateJpaRepositoryTest에서 가져와서..
줄바꿈 수정하는 김에 해당 클래스도 같이 수정해서 올리겠습니다.

Comment on lines 323 to 324
() -> assertThat(actual.getContent()).containsExactlyInAnyOrder(templateRepository.fetchById(1L),
templateRepository.fetchById(2L))
Copy link
Contributor

Choose a reason for hiding this comment

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

⚡️ 전체적으로 통일을 위한 확인이 필요할 것 같아용

Copy link
Contributor

@zangsu zangsu 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 84 to 88
assertAll(
() -> assertThat(actual.getTitle()).isEqualTo(templateRequest.title()),
() -> assertThat(actual.getMember()).isEqualTo(member),
() -> assertThat(actual.getCategory()).isEqualTo(category)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

Repository 테스트를 항상 잘 작성한다면 굳이 체크를 할 필요가 없을 것 같기는 합니다만....
저도 고민이 되네요.
서비스 계층의 특별한 역할이 존재하는 것이 아니라, 거의 Repository 메서드로 포워딩 하는 느낌이라서 무엇을 테스트 해야 하나 하는 고민도 들고요.

저는 데이터베이스에 추가되는지 확인하는 로직은 있으면 좋고, 없어도 그만~ 의 느낌인 것 같네요!

Comment on lines 284 to 287
template.getMember().getId().equals(member1.getId())
&& (template.getTitle().contains(keyword) || template.getDescription()
.contains(keyword)))
);
Copy link
Contributor

Choose a reason for hiding this comment

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

저도 몰리 의견에 한 표 추가합니다!

6.4. 줄바꿈 허용 위치
네이버 핵데이 컨벤션인데요. 여기서도 연산자 앞에서 줄바꿈을 규칙으로 지정하고 있어요.

조건 연산자로 연결된 줄이 길어질 경우, 조건 연산자 앞에서 개행을 해주면 훨씬 가독성이 좋아지는 것 같네용

Copy link
Contributor

@zeus6768 zeus6768 left a comment

Choose a reason for hiding this comment

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

테스트 코드가 정말 많네요. 작성하느라 고생 많았어요 😭

다른 분들이 변경사항에 대해 충분히 언급하신 것 같아, 저는 의견만 이모지로 표현했습니다.


테스트 코드는 해당 클래스의 명세서와도 같고, 테스트 코드를 봤을 때 해당 클래스를 어떻게 사용하는거구나, 어떤 에러가 발생할 수 있구나 등을 알 수 있게 하는 것이 목적이라고 생각하기 때문입니다.

테스트 코드는 클래스의 명세가 아니라 기능의 명세라고 정정하고 싶어요.

클래스의 명세라는 관점으로 접근하면, 그 클래스의 구현까지 고려해야할 것 같다는 생각이 들기 때문입니다.

반면 저는 원하는 기능만 올바르게 동작하는지 확인하면 된다고 생각해요.

서비스는 DB에 의존하고 있으니 서비스 테스트에서 DB에 잘 저장되었는지까지 확인해야 할까요?

그렇다면 어떤 객체를 테스트할 때 그 객체의 모든 의존성이 발생할 수 있는 예외를 검증해야 한다는 말인데, 이건 말이 안 된다고 생각해요.

단위 테스트 책에서 리팩토링 내성에 관한 챕터를 읽어보면 좋을 것 같습니다.

다른 의견 있다면 답변 부탁드려요~!

Comment on lines 84 to 88
assertAll(
() -> assertThat(actual.getTitle()).isEqualTo(templateRequest.title()),
() -> assertThat(actual.getMember()).isEqualTo(member),
() -> assertThat(actual.getCategory()).isEqualTo(category)
);
Copy link
Contributor

Choose a reason for hiding this comment

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

저는 findAll 메서드의 결과만 놓고 검증해야 한다고 생각합니다.

구체적인 로직을 몰라도 테스트를 할 수 있어야 한다고 생각하기 때문입니다.

assertThat(templateRepository.findAll()).isEmpty();
@Nested
@DisplayName("검색 기능")
class FindAll {
Copy link
Contributor

Choose a reason for hiding this comment

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

pageable이 있는 경우와 없는 경우를 먼저 테스트해서 Pageable이 필수 인자라는 것을 보여주면 좋을 것 같아요.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

좋은 테스트네요!! 다만 현재는 Pageable에 대한 null 체크가 없어서 NPE가 발생하고 있습니다.
추후에 null 체크 로직이 필요할 것 같아서 @disabled 처리해놨습니다!

Copy link
Contributor

@zeus6768 zeus6768 left a comment

Choose a reason for hiding this comment

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

고생 많았습니다 🚀

Copy link
Contributor

@kyum-q kyum-q left a comment

Choose a reason for hiding this comment

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

초롱 수고하셨어요 ~

Copy link
Contributor

@zangsu zangsu left a comment

Choose a reason for hiding this comment

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

고생했습니다 초롱~!
이번 미션도 여기서 approve 하겠습니다!
다음 미션도 파이팅입니다 🔥

Copy link
Contributor

@jminkkk jminkkk 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 +169 to +174
String keyword = null;
Long categoryId = null;
List<Long> tagIds = null;
Pageable pageable = PageRequest.of(0, 10);

Page<Template> actual = sut.findAll(memberId, keyword, categoryId, tagIds, pageable);
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 +156 to +157
@DisplayName("검색 기능")
class FindAll {
Copy link
Contributor

Choose a reason for hiding this comment

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

맞아요~ 요청드린 것 중에 여러개가 제가 작성한 것도 알고 있어요
그래서 제가 더 정정해야겠다고 생각했어요


저는 템플릿을 조회하는 기능 중에 키워드 검색이 있는 것 같다고 생각을 했었어요.
또 검색 보다는 조회가 더 큰 범위라고 생각해서 정정 부탁드렸습니답...

마이페이지에서 내 글만 조회를 하거나, 필터링이 전혀 없이 단순 GET /templates 을 한다고 생각을 했을 때 오히려 조회가 더 명확할 것 같아서요. 그런데 사람마다 다르게 느껴질 수도 있겠네요 🤔

제 의견에 대한 설명이 없어서 의도와 다르게 전달된 것 같아서 의견 전달만 명확하게 드려봅니다~ 🔥

@kyum-q kyum-q merged commit e107f89 into dev/be Sep 20, 2024
7 checks passed
@kyum-q kyum-q deleted the test/645-template-service branch September 20, 2024 13:27
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
BE 백엔드 refactor 요구사항이 바뀌지 않은 변경사항
Projects
Status: Weekend Done
Development

Successfully merging this pull request may close these issues.

5 participants