💻문제점
테스트 코드를 작성하던 중 문제가 발생했다.
@Test
@DisplayName("금일 섭취량 조회")
void searchDailyIntakeNutrientsTest() {
// given
Long memberId = member.getId();
Meal meal = meals.get(0);
mealLogs = List.of(
MealLogFixture.BREAKFAST.get(meals, member),
MealLogFixture.LUNCH.get(meals, member));
int expectedSize = meals.size() * mealLogs.size();
LocalDate date = mealLogs.get(0).getModifiedAt().toLocalDate();
LocalDateTime startDate = date.atStartOfDay();
LocalDateTime endDate = date.atTime(LocalTime.MAX);
given(memberQueryService.search(memberId)).willReturn(member);
given(mealLogRepository.findAllByMemberIdAndModifiedAtBetween(memberId, startDate, endDate))
.willReturn(mealLogs);
// when
IntakeNutrients intakeNutrients =
nutrientsQueryService.searchDailyIntakeNutrients(memberId, date);
// then
assertThat(intakeNutrients.calorie()).isEqualTo(meal.getCalorie() * expectedSize);
assertThat(intakeNutrients.carbs()).isEqualTo(meal.getCarbs() * expectedSize);
assertThat(intakeNutrients.protein()).isEqualTo(meal.getProtein() * expectedSize);
assertThat(intakeNutrients.fat()).isEqualTo(meal.getFat() * expectedSize);
}
modifiedAt이 null이라는 것이다.
MealLogFixture.java
public enum MealLogFixture {
BREAKFAST(MealType.BREAKFAST),
BREAKFAST_SNACK(MealType.BREAKFAST_SNACK),
LUNCH(MealType.LUNCH),
LUNCH_SNACK(MealType.LUNCH_SNACK),
DINNER(MealType.DINNER),
DINNER_SNACK(MealType.DINNER_SNACK);
private MealType mealType;
MealLogFixture(MealType mealType) {
this.mealType = mealType;
}
public MealLog get(List<Meal> meals, Member member) {
MealLog mealLog = MealLog.builder().mealType(mealType).member(member).build();
meals.forEach(mealLog::addMeal);
return mealLog;
}
}
여기서 Builder를 통해 MealLog를 생성할 때, createdAt이나 modifiedAt은 private 필드라 설정해줄 수 없다.
해당 필드는 DB에 save 또는 update될 때 자동으로 설정되기 때문에, 테스트 로직에서 save를 하지 않는 나로서는 고민이었다...
🔍해결
자바의 리플렉션을 사용하면 private 필드에 접근할 수 있다.
리플렉션
구체적인 클래스 타입을 몰라도, 클래스의 메서드, 타입, 변수들에 접근할 수 있도록 해주는 자바 API
접근 제어자(public, private...)와 무관하게 호출이 가능
MealLogFixture 클래스에 다음과 같은 메서드를 추가했다.
public MealLog getWithDate(List<Meal> meals, Member member, LocalDate date) {
MealLog mealLog = MealLog.builder().mealType(mealType).member(member).build();
meals.forEach(mealLog::addMeal);
return setModifiedAt(mealLog, date);
}
private MealLog setModifiedAt(MealLog mealLog, LocalDate date) {
Field modifiedAt = ReflectionUtils.findField(MealLog.class, "modifiedAt");
ReflectionUtils.makeAccessible(modifiedAt);
ReflectionUtils.setField(modifiedAt, mealLog, date.atStartOfDay());
return mealLog;
}
spring에서 제공하는 ReflectionUtils를 사용해 리플렉션 API를 쉽게 사용할 수 있다.
1. ReflectionUtils의 findField를 사용하여 MealLog.class에서 modifiedAt 필드를 가져온다.
2. makeAccessible를 통해 private 필드에 접근이 가능하도록 한다.
3. setField를 통해 mealLog의 modifiedAt 필드를 date.atStartOfDay()로 설정한다.
LocalDate를 인자로 받는 이유는 나중에 테스트할 경우 1년 전의 mealLog도 필요하기 때문이다.
@Test
@DisplayName("금일 섭취량 조회")
void searchDailyIntakeNutrientsTest() {
// given
Long memberId = member.getId();
Meal meal = meals.get(0);
mealLogs =
List.of(
MealLogFixture.BREAKFAST.getWithDate(meals, member, LocalDate.now()), //변경
MealLogFixture.LUNCH.getWithDate(meals, member, LocalDate.now())); //변경
int expectedSize = meals.size() * mealLogs.size();
LocalDate date = mealLogs.get(0).getModifiedAt().toLocalDate();
LocalDateTime startDate = date.atStartOfDay();
LocalDateTime endDate = date.atTime(LocalTime.MAX);
given(memberQueryService.search(memberId)).willReturn(member);
given(mealLogRepository.findAllByMemberIdAndModifiedAtBetween(memberId, startDate, endDate))
.willReturn(mealLogs);
// when
IntakeNutrients intakeNutrients =
nutrientsQueryService.searchDailyIntakeNutrients(memberId, date);
// then
assertThat(intakeNutrients.calorie()).isEqualTo(meal.getCalorie() * expectedSize);
assertThat(intakeNutrients.carbs()).isEqualTo(meal.getCarbs() * expectedSize);
assertThat(intakeNutrients.protein()).isEqualTo(meal.getProtein() * expectedSize);
assertThat(intakeNutrients.fat()).isEqualTo(meal.getFat() * expectedSize);
}
테스트가 성공적으로 동작한다!
728x90
'TIL' 카테고리의 다른 글
[TIL - 20231222] searchWeeklyIntakeCalories 로직 개선 (0) | 2023.12.22 |
---|---|
[TIL-20231222] Illegal pop() with non-matching JdbcValuesSourceProcessingState (0) | 2023.12.22 |
[TIL - 20230914~15] Github Actions+Docker CI/CD 트러블슈팅 (0) | 2023.09.15 |
[커뮤 프로젝트] 영상 파일 삭제 로직 (동기, 비동기 처리) (0) | 2023.07.04 |
[커뮤 프로젝트] 서버 아키텍처 변경을 통한 성능 개선 (0) | 2023.07.02 |