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

CategoryService 테스트 #656

Merged
merged 19 commits into from
Sep 22, 2024
Merged
Changes from all commits
Commits
Show all changes
19 commits
Select commit Hold shift + click to select a range
90b95b8
test: 카테고리 생성 테스트 가독성 보완
zangsu Sep 17, 2024
8cd2356
test: 각각의 테스트 하는 메서드마다 Nested 테스트로 변경
zangsu Sep 17, 2024
b61632c
test: findAllByMember 메서드 테스트 추가
zangsu Sep 17, 2024
50dfc51
test: 단건 조회 메서드 테스트 작성
zangsu Sep 17, 2024
d27d33a
test: 카테고리 수정 메서드 테스트 작성
zangsu Sep 17, 2024
13fcd51
docs: 코드 리뷰를 위해 주석 추가
zangsu Sep 17, 2024
c4b196f
docs: 리뷰 코멘트를 위해 추가했던 주석 삭제
zangsu Sep 17, 2024
091eaed
test: fake 데이터베이스 사용 제거
zangsu Sep 17, 2024
56371d4
test: 사용하지 않는 import 문 제거
zangsu Sep 17, 2024
36705fc
test: 테스트의 예외 타입 변경
zangsu Sep 17, 2024
a44521e
refactor: 필요 없는 주석 삭제
zangsu Sep 20, 2024
7ba2589
refactor: 테스트 내 변수명 통일
zangsu Sep 20, 2024
a464827
refactor: 저장된 카테고리의 멤버 정보까지 확인하도록 변경
zangsu Sep 20, 2024
7fa7938
refactor: 성공 메서드를 묶어두기 위해 메서드 위치 변경
zangsu Sep 20, 2024
ac3e9d1
refactor: 성공 테스트에서 확인하는 값을 추가
zangsu Sep 20, 2024
1704cd0
refactor: 저장된 카테고리를 Repository 에서 조회
zangsu Sep 20, 2024
b08fb67
docs: 컨벤션 적용
zangsu Sep 20, 2024
8c248a6
test: 카테고리가 존재하지 않으면 빈 리스트를 반환한다.
zangsu Sep 20, 2024
81e2e23
refactor: 실패하는 테스트 disabled
zangsu Sep 20, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
186 changes: 163 additions & 23 deletions backend/src/test/java/codezap/category/service/CategoryServiceTest.java
Original file line number Diff line number Diff line change
@@ -1,78 +1,138 @@
package codezap.category.service;

import static org.assertj.core.api.Assertions.assertThat;
import static org.assertj.core.api.Assertions.assertThatCode;
import static org.assertj.core.api.Assertions.assertThatThrownBy;
import static org.junit.jupiter.api.Assertions.assertAll;

import jakarta.transaction.Transactional;

import org.junit.jupiter.api.Disabled;
import org.junit.jupiter.api.DisplayName;
import org.junit.jupiter.api.Nested;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.dao.InvalidDataAccessApiUsageException;

import codezap.category.domain.Category;
import codezap.category.dto.request.CreateCategoryRequest;
import codezap.category.dto.request.UpdateCategoryRequest;
import codezap.category.dto.response.CreateCategoryResponse;
import codezap.category.dto.response.FindAllCategoriesResponse;
import codezap.category.dto.response.FindCategoryResponse;
import codezap.category.repository.CategoryRepository;
import codezap.category.repository.FakeCategoryRepository;
import codezap.global.DatabaseIsolation;
import codezap.global.exception.CodeZapException;
import codezap.member.domain.Member;
import codezap.member.fixture.MemberFixture;
import codezap.member.repository.FakeMemberRepository;
import codezap.member.repository.MemberRepository;

@SpringBootTest
@DatabaseIsolation
class CategoryServiceTest {

private final CategoryRepository categoryRepository = new FakeCategoryRepository();
private final MemberRepository memberRepository = new FakeMemberRepository();
@Autowired
private CategoryRepository categoryRepository;

@Autowired
private MemberRepository memberRepository;

private final CategoryService categoryService = new CategoryService(categoryRepository);
@Autowired
private CategoryService categoryService;

@Nested
@DisplayName("카테고리 생성 테스트")
class createCategoryTest {
class CreateCategoryTest {

@Test
@DisplayName("카테고리 생성 성공")
@Transactional
void createCategorySuccess() {
Member member = memberRepository.save(MemberFixture.memberFixture());
CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest("category1");
String categoryName = "categoryName";
CreateCategoryRequest request = new CreateCategoryRequest(categoryName);

CreateCategoryResponse response = categoryService.create(member, createCategoryRequest);
CreateCategoryResponse response = categoryService.create(member, request);
Category savedCategory = categoryRepository.fetchById(response.id());

assertThat(response.id()).isEqualTo(1L);
assertAll(
() -> assertThat(response.id()).isEqualTo(1L),
() -> assertThat(savedCategory.getName()).isEqualTo(categoryName),
() -> assertThat(savedCategory.getMember()).isEqualTo(member)
);
}

@Test
@DisplayName("카테고리 생성 성공: 다른 멤버, 중복된 이름의 카테고리 이름 생성")
@Transactional
void createCategorySuccessWithOtherMemberAndSameName() {
Member member = memberRepository.save(MemberFixture.memberFixture());
Member otherMember = memberRepository.save(MemberFixture.createFixture("otherMember"));
String duplicatedCategoryName = "category";
jminkkk marked this conversation as resolved.
Show resolved Hide resolved
categoryRepository.save(new Category(duplicatedCategoryName, member));

CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest(duplicatedCategoryName);
CreateCategoryResponse createCategoryResponse = categoryService.create(otherMember, createCategoryRequest);
Category savedCategory = categoryRepository.fetchById(createCategoryResponse.id());

assertAll(
() -> assertThat(createCategoryResponse.id()).isEqualTo(2L),
() -> assertThat(savedCategory.getName()).isEqualTo(duplicatedCategoryName),
() -> assertThat(savedCategory.getMember()).isEqualTo(otherMember)
);
}

@Test
@DisplayName("카테고리 생성 실패: 동일한 멤버, 중복된 이름의 카테고리 이름 생성")
void createCategoryFailWithSameMemberAndDuplicateName() {
String duplicatedCategoryName = "category";
Member member = memberRepository.save(MemberFixture.memberFixture());
String duplicatedCategoryName = "category";
categoryRepository.save(new Category(duplicatedCategoryName, member));

CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest(duplicatedCategoryName);

assertThatThrownBy(
() -> categoryService.create(member, createCategoryRequest))
assertThatThrownBy(() -> categoryService.create(member, createCategoryRequest))
.isInstanceOf(CodeZapException.class)
.hasMessage("이름이 " + duplicatedCategoryName + "인 카테고리가 이미 존재합니다.");
}
}

@Nested
@DisplayName("멤버로 카테고리 조회 테스트")
class FindAllCategoryByMemberTest {

@Test
@DisplayName("카테고리 생성 성공: 다른 멤버, 중복된 이름의 카테고리 이름 생성")
void createCategorySuccessWithOtherMemberAndSameName() {
@DisplayName("성공")
void success() {
Member member = memberRepository.save(MemberFixture.memberFixture());
categoryRepository.save(new Category("category", member));
Category category1 = categoryRepository.save(new Category("category1", member));
Category category2 = categoryRepository.save(new Category("category2", member));
Comment on lines +108 to +109
Copy link
Contributor

Choose a reason for hiding this comment

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

카테고리도 Fixture가 있습니다! 활용하시면 좋을 것 같네용

Copy link
Contributor Author

Choose a reason for hiding this comment

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

픽스쳐를 사용하는 건 좋은 의견이군요!
그런데, 지금은 member 의 서로 다른 두 카테고리를 저장해야 해요.
픽스쳐는 MemberFixture.getFirstMember() 의 카테고리 하나와 MemberFixture.getSecondMember() 의 카테고리 하나밖에 존재하지 않아서 직접 생성하는 것이 가장 좋을 것 같습니다!

Member otherMember = memberRepository.save(MemberFixture.createFixture("otherMember"));
Category category3 = categoryRepository.save(new Category("notMyCategory", otherMember));

CreateCategoryRequest createCategoryRequest = new CreateCategoryRequest("category");
FindAllCategoriesResponse categoryByMember = categoryService.findAllByMember(member);

assertThat(categoryService.create(otherMember, createCategoryRequest).id())
.isEqualTo(2L);
assertThat(categoryByMember.categories()).hasSize(2)
.containsExactly(FindCategoryResponse.from(category1), FindCategoryResponse.from(category2))
.doesNotContain(FindCategoryResponse.from(category3));
}

@Test
@DisplayName("카테고리 전체 조회 테스트")
@DisplayName("성공 : 존재하지 않는 멤버로 조회를 하면 DB 에러가 발생한다.")
void failWithNotExistMember() {
Member notExistMember = MemberFixture.createFixture("notExist");

assertThatThrownBy(() -> categoryService.findAllByMember(notExistMember))
.isInstanceOf(InvalidDataAccessApiUsageException.class);
}
}

@Nested
@DisplayName("카테고리 전체 조회 테스트")
class FindAllCategoryTest {
Comment on lines +131 to +132
Copy link
Contributor

Choose a reason for hiding this comment

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

카테고리 없을 때 빈 리스트 반환하는 것도 추가해주심 좋을 것 같아용


@Test
@DisplayName("성공")
void findAllCategoriesSuccess() {
Member member = memberRepository.save(MemberFixture.memberFixture());

Expand All @@ -84,8 +144,49 @@ void findAllCategoriesSuccess() {
assertThat(findAllCategoriesResponse.categories()).hasSize(2);
}

@Test
@DisplayName("성공 : 카테고리가 존재하지 않으면 빈 리스트를 반환한다.")
void findAllCategoriesEmptyList() {

FindAllCategoriesResponse findAllCategoriesResponse = categoryService.findAll();

assertThat(findAllCategoriesResponse.categories()).isEmpty();
}
}

@Nested
@DisplayName("카테고리 단건 조회 테스트")
class FetchByIdTest {

@Test
@DisplayName("성공")
void success() {
Member member = memberRepository.save(MemberFixture.memberFixture());
Category savedCategory = categoryRepository.save(new Category("categoryName", member));

Category actual = categoryService.fetchById(savedCategory.getId());

assertThat(actual).isEqualTo(savedCategory);
}

@Test
@DisplayName("실패: 존재하지 않는 id 값으로 카테고리 조회")
void failWithNotSavedId() {
long notSavedCategoryId = 100L;

assertThatThrownBy(() -> categoryService.fetchById(notSavedCategoryId))
.isInstanceOf(CodeZapException.class)
.hasMessage("식별자 " + notSavedCategoryId + "에 해당하는 카테고리가 존재하지 않습니다.");
}
}

@Nested
@DisplayName("카테고리 수정 테스트")
class UpdateCategoryTest {

@Test
@DisplayName("카테고리 수정 성공")
Copy link
Contributor Author

Choose a reason for hiding this comment

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

수정 성공 테스트가 현재 실패하는데요.
이유를 확인해 보니 Member.equals() 메서드의 아래 부분이 문제였습니다.

        if (o == null || getClass() != o.getClass()) {
            return false;
        }

현재 CategoryMember 필드에는 lazy loading 이 걸려있습니다.
때문에 프록시 객체가 Member 필드로 들어가게 되고, 클래스 비교에서 false 가 반환되는 것이 문제입니다.

프로덕션 코드의 수정이 일어나야 해 이슈에 남겨두고 넘어가겠습니다.

Copy link
Contributor

Choose a reason for hiding this comment

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

원활한 CI 진행을 위해 @disabled 처리를 해놓는 건 어떤가요?

Copy link
Contributor

@zeus6768 zeus6768 Sep 19, 2024

Choose a reason for hiding this comment

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

#650, #664 관련 이슈 코멘트합니다.

@Disabled
void updateCategorySuccess() {
String updateCategoryName = "updateName";
Member member = memberRepository.save(MemberFixture.memberFixture());
Expand All @@ -102,14 +203,53 @@ void updateCategorySuccess() {
void updateCategoryFailWithUnauthorized() {
Member member = memberRepository.save(MemberFixture.memberFixture());
Category savedCategory = categoryRepository.save(new Category("category1", member));

Member otherMember = memberRepository.save(MemberFixture.createFixture("otherMember"));

UpdateCategoryRequest request = new UpdateCategoryRequest("updateName");
assertThatCode(
() -> categoryService.update(otherMember, savedCategory.getId(), request))

assertThatThrownBy(() -> categoryService.update(otherMember, savedCategory.getId(), request))
.isInstanceOf(CodeZapException.class)
.hasMessage("해당 카테고리에 대한 권한이 없습니다.");
}

@Test
@DisplayName("카테고리 수정 실패: 이미 존재하는 카테고리 이름")
void duplicatedCategoryName() {
Member member = memberRepository.save(MemberFixture.memberFixture());
Category category1 = categoryRepository.save(new Category("category1", member));
Category category2 = categoryRepository.save(new Category("category2", member));

UpdateCategoryRequest request = new UpdateCategoryRequest(category1.getName());

assertThatThrownBy(() -> categoryService.update(member, category2.getId(), request))
.isInstanceOf(CodeZapException.class)
.hasMessage("이름이 " + category1.getName() + "인 카테고리가 이미 존재합니다.");
}

@Test
@DisplayName("카테고리 수정 실패: 현재와 동일한 카테고리 이름")
void notChangedCategoryName() {
Member member = memberRepository.save(MemberFixture.memberFixture());
Category category = categoryRepository.save(new Category("category", member));

UpdateCategoryRequest request = new UpdateCategoryRequest(category.getName());

assertThatThrownBy(() -> categoryService.update(member, category.getId(), request))
.isInstanceOf(CodeZapException.class)
.hasMessage("이름이 " + category.getName() + "인 카테고리가 이미 존재합니다.");
}

@Test
@DisplayName("카테고리 수정 실패: 존재하지 않는 카테고리 id")
void notSavedCategoryId() {
Member member = memberRepository.save(MemberFixture.memberFixture());

UpdateCategoryRequest request = new UpdateCategoryRequest("categoryName");
long notSavedId = 100L;

assertThatThrownBy(() -> categoryService.update(member, notSavedId, request))
.isInstanceOf(CodeZapException.class)
.hasMessage("식별자 " + notSavedId + "에 해당하는 카테고리가 존재하지 않습니다.");
}
}
}