늦은 프로그래밍 이야기

230213 TIL (최종프로젝트) 본문

내일배움캠프/TIL, WIL

230213 TIL (최종프로젝트)

한정규 2023. 2. 13. 23:58

프로젝트

Category CRUD

오늘부터 프로젝트의 기능들을 구현하기 시작했다. 내가 하기로 한 작업에는 도메인 단위로 크게는 Restaurant에 관련된 작업이고 작게는 Category CRUD, Menu CRUD, Restaurant 조회(일반조회, 키워드검색, 현재위치 기반 반경 3km 이내 조회) 가 있다.

일단 Restaurant에 Category 값을 가지고 있어야 하기 때문에 최우선 순위라고 생각이 들어 Category CRUD부터 작업을 하게 되었다. 이미 저저번 프로젝트에서 카테고리를 구현했었던 터라 그리 어렵지 않게 구현할 수 있었다.

기능구현

public class Category {
   @Id
   @GeneratedValue(strategy = GenerationType.IDENTITY)
   @Column(name = "category_id")
   private Long id;

   private Long parentId;

   @Column(nullable = false)
   private String name;
}

저번과 다르게 depth를 주지 않았고, parentId 값만 주어 LinkedList 방식처럼 자식 카테고리가 부모 카테고리를 가리키는 방식으로 구현하였다. 생성, 수정, 삭제는 카테고리 내의 필드가 많지 않고 복잡한 로직이 없어서 그리 어렵지 않게 해결할 수 있었고, 조회에서 기존 방식과 다르게 부모 카테고리 목록을 조회하는 메소드와 하나의 부모카테고리 내의 모든 자식 카테고리들을 조회하는 메소드 두가지로 구현하는 것에서 조금 어려움이 있었다.

총 계층이 3개 밖에 되지 않아 부모 카테고리를 제외하고는 2계층이어서 최대 2중 반복문으로 카테고리 목록을 가져올 수 있어서 해당 방법을 채택하였는데, 아래로 타고 들어가는 방법을 사용하고 2중 반복문을 사용하지 않아도 될 것 같지만 프론트를 구현해보고 추후 성능 개선을 할 때에 이슈가 되면 다시 작업하기로 하고 그대로 진행하기로 하였다.

public ChildCategoryResponse(List<Category> categories, Long categoryId) {
   this.categoryId = categoryId;

   String name = "";
   for (Category category : categories) {
      if (Objects.equals(category.getId(), categoryId)) {
         name = category.getName();
      }
   }
   this.name = name;

List<ChildCategoryResponse> categoryResponses = new ArrayList<>();
   for (Category category : categories) {
      if (Objects.equals(category.getParentId(), categoryId)) {
         categoryResponses.add(new ChildCategoryResponse(categories, category.getId()));
      }
   }
   this.childCategories = categoryResponses;
}

저번에 카테고리를 구현한 방식에서 depth만 빠진 방식이어서 시간이 오래 걸리지 않고 구현할 수 있었지만, 이번 프로젝트에 테스트 코드가 필수 요소여서 테스트 코드를 작성하는데 많은 어려움을 겪었다.


테스트 코드

@Test
@DisplayName("하위 카테고리 조회")
void getChildCategories() {
   // given
   GetChildCategoryServiceRequest request = mock(GetChildCategoryServiceRequest.class);
   Category category1 = mock(Category.class);
   Category category2 = mock(Category.class);

    when(request.getParentId()).thenReturn(1L);

    when(category1.getId()).thenReturn(1L);
    when(category1.getParentId()).thenReturn(null);
    when(category1.getName()).thenReturn("parent");

    when(category2.getId()).thenReturn(2L);
    when(category2.getParentId()).thenReturn(1L);
    when(category2.getName()).thenReturn("child");

    List<Category> categories = new ArrayList<>();
    categories.add(category1);
    categories.add(category2);

    when(categoryRepository.findAll()).thenReturn(categories);

   // when
   ChildCategoryResponse categoryResponse = categoryService.getChildCategories(request);

   // then
    assertEquals("parent", categoryResponse.getName());
    assertEquals("child", categoryResponse.getChildCategories().get(0).getName());
}

제대로 작성된 코드인지는 확실하지 않다. 테스트 코드를 많이 작성하지 않기도 하였고, 가뜩이나 익숙하지 않은데다 반복문에 재귀까지 구현한 코드를 테스트 코드를 작성하려니 좀처럼 쉽게 되지 않았다. 정말 많은 시간을 할애하였고, 해당 테스트 코드를 작성하면서 테스트 코드의 전체적인 흐름을 알게된 것 같다.


Comments