Skip to content

Commit ea17e6d

Browse files
authored
Merge pull request #172 from SWU-Elixir/test/157-recipe
test: RecommendationService 테스트 코드 작성
2 parents 75e5123 + efd844e commit ea17e6d

File tree

1 file changed

+236
-0
lines changed

1 file changed

+236
-0
lines changed
Lines changed: 236 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,236 @@
1+
package BE_Elixir.Elixir.domain.recommendation.service;
2+
3+
import BE_Elixir.Elixir.domain.ingredient.entity.Ingredient;
4+
import BE_Elixir.Elixir.domain.ingredient.repository.IngredientRepository;
5+
import BE_Elixir.Elixir.domain.member.entity.Member;
6+
import BE_Elixir.Elixir.domain.recipe.dto.MaterialDTO;
7+
import BE_Elixir.Elixir.domain.recipe.dto.request.RecipeRequestDTO;
8+
import BE_Elixir.Elixir.domain.recipe.entity.Recipe;
9+
import BE_Elixir.Elixir.domain.recipe.entity.RecipeIngredient;
10+
import BE_Elixir.Elixir.domain.recipe.repository.RecipeEventRepository;
11+
import BE_Elixir.Elixir.domain.recipe.repository.RecipeRepository;
12+
import BE_Elixir.Elixir.domain.recommendation.dto.RecommendationResponseDTO;
13+
import BE_Elixir.Elixir.global.enums.CategorySlowAging;
14+
import BE_Elixir.Elixir.global.enums.CategoryType;
15+
import BE_Elixir.Elixir.global.enums.Difficulty;
16+
import BE_Elixir.Elixir.global.redis.RedisRecipeService;
17+
import org.junit.jupiter.api.BeforeEach;
18+
import org.junit.jupiter.api.DisplayName;
19+
import org.junit.jupiter.api.Nested;
20+
import org.junit.jupiter.api.Test;
21+
import org.junit.jupiter.api.extension.ExtendWith;
22+
import org.mockito.InjectMocks;
23+
import org.mockito.Mock;
24+
import org.mockito.Mockito;
25+
import org.mockito.junit.jupiter.MockitoExtension;
26+
import org.springframework.data.domain.PageRequest;
27+
import org.springframework.data.domain.Pageable;
28+
29+
import java.time.Duration;
30+
import java.util.*;
31+
32+
import static org.assertj.core.api.Assertions.*;
33+
import static org.mockito.ArgumentMatchers.*;
34+
import static org.mockito.BDDMockito.*;
35+
36+
37+
@ExtendWith(MockitoExtension.class)
38+
@DisplayName("RecommendationService 테스트")
39+
class RecommendationServiceTest {
40+
@InjectMocks
41+
RecommendationService recommendationService;
42+
43+
@Mock RecipeRepository recipeRepository;
44+
@Mock RedisRecipeService redisRecipeService;
45+
@Mock RecipeEventRepository recipeEventRepository;
46+
@Mock IngredientRepository ingredientRepository;
47+
48+
private RecipeRequestDTO requestDTO;
49+
private Recipe recipe;
50+
private Member member;
51+
private Pageable pageable;
52+
53+
@BeforeEach
54+
void setUp() {
55+
member = Member.builder()
56+
.id(1L)
57+
.email("test@example.com")
58+
.nickname("testUser")
59+
.build();
60+
61+
member.setMealStyle_채소위주(true);
62+
member.setAllergy_밀(true);
63+
member.setRecipeStyle_한식(true);
64+
member.setReason_항산화강화(true);
65+
66+
pageable = PageRequest.of(0, 10);
67+
68+
requestDTO = createSampleRecipeRequestDTO();
69+
70+
recipe = Recipe.from(requestDTO, member);
71+
Ingredient ingredient = new Ingredient();
72+
ingredient.setId(10L);
73+
ingredient.setName("감자");
74+
75+
RecipeIngredient recipeIngredient = new RecipeIngredient(recipe, ingredient);
76+
recipe.setIngredientTags(List.of(recipeIngredient));
77+
}
78+
79+
private RecipeRequestDTO createSampleRecipeRequestDTO() {
80+
RecipeRequestDTO dto = new RecipeRequestDTO();
81+
dto.setTitle("감자조림");
82+
dto.setDescription("감자조림에 대한 설명");
83+
dto.setCategoryType(CategoryType.한식);
84+
dto.setCategorySlowAging(CategorySlowAging.항산화강화);
85+
dto.setDifficulty(Difficulty.보통);
86+
dto.setTimeHours(1);
87+
dto.setTimeMinutes(20);
88+
dto.setIngredientTagIds(List.of(10L));
89+
90+
MaterialDTO ingredient = new MaterialDTO("감자", "2", "개");
91+
MaterialDTO seasoning1 = new MaterialDTO("간장", "2", "큰술");
92+
MaterialDTO seasoning2 = new MaterialDTO("설탕", "1", "큰술");
93+
dto.setIngredients(List.of(ingredient));
94+
dto.setSeasonings(List.of(seasoning1, seasoning2));
95+
96+
dto.setStepDescriptions(List.of("1단계"));
97+
dto.setTips("팁");
98+
dto.setAllergies(List.of("우유", "밀"));
99+
100+
return dto;
101+
}
102+
103+
@Nested
104+
@DisplayName("사용자 맞춤형 레시피 추천 테스트")
105+
class GetRecommendationsForUserTests {
106+
107+
@Test
108+
@DisplayName("성공: 캐시에서 추천 결과가 존재하면 캐시 반환")
109+
void returnsCachedRecommendations() {
110+
// given
111+
List<RecommendationResponseDTO> cached = List.of(
112+
new RecommendationResponseDTO(new Recipe(), false)
113+
);
114+
given(redisRecipeService.getCachedRecommendations(member.getId())).willReturn(cached);
115+
116+
// when
117+
List<RecommendationResponseDTO> result = recommendationService.getRecommendationsForUser(member);
118+
119+
// then
120+
assertThat(result).isEqualTo(cached);
121+
then(redisRecipeService).should(times(1)).getCachedRecommendations(member.getId());
122+
then(recipeRepository).should(never()).findAll();
123+
}
124+
125+
@Test
126+
@DisplayName("성공: 캐시 없고, 필터링 후 추천 결과 반환 및 캐싱")
127+
void returnsFilteredRecommendationsAndCaches() {
128+
// given
129+
given(redisRecipeService.getCachedRecommendations(member.getId())).willReturn(null);
130+
131+
Recipe recipe1 = Mockito.mock(Recipe.class);
132+
given(recipe1.getId()).willReturn(10L);
133+
given(recipe1.getAllergyList()).willReturn(List.of("우유"));
134+
given(recipe1.getIngredientTags()).willReturn(List.of());
135+
given(recipe1.getCategoryType()).willReturn(CategoryType.한식);
136+
given(recipe1.getCategorySlowAging()).willReturn(CategorySlowAging.항산화강화);
137+
138+
List<Recipe> allRecipes = List.of(recipe1);
139+
given(recipeRepository.findAll()).willReturn(allRecipes);
140+
141+
given(recipeEventRepository.existsByRecipeIdAndMemberIdAndScrapFlagTrue(10L, member.getId())).willReturn(true);
142+
143+
// when
144+
List<RecommendationResponseDTO> result = recommendationService.getRecommendationsForUser(member);
145+
146+
// then
147+
assertThat(result).hasSize(1);
148+
assertThat(result.get(0).getScrappedByCurrentUser()).isTrue();
149+
150+
then(redisRecipeService).should().cacheRecommendations(eq(member.getId()), anyList(), eq(Duration.ofHours(1)));
151+
}
152+
153+
@Test
154+
@DisplayName("성공: 필터링된 결과 없으면 전체 중 랜덤 3개 추천")
155+
void returnsRandomWhenNoFiltered() {
156+
// given
157+
given(redisRecipeService.getCachedRecommendations(member.getId())).willReturn(null);
158+
159+
Recipe recipe1 = new Recipe();
160+
recipe1.setCategoryType(CategoryType.한식);
161+
recipe1.setCategorySlowAging(CategorySlowAging.항산화강화);
162+
recipe1.setIngredientTags(new ArrayList<>());
163+
164+
Recipe recipe2 = new Recipe();
165+
recipe2.setCategoryType(CategoryType.중식);
166+
recipe2.setCategorySlowAging(CategorySlowAging.항산화강화);
167+
recipe2.setIngredientTags(new ArrayList<>());
168+
169+
Recipe recipe3 = new Recipe();
170+
recipe3.setCategoryType(CategoryType.디저트);
171+
recipe3.setCategorySlowAging(CategorySlowAging.혈당조절);
172+
recipe3.setIngredientTags(new ArrayList<>());
173+
174+
Recipe recipe4 = new Recipe();
175+
recipe4.setCategoryType(CategoryType.양식);
176+
recipe4.setCategorySlowAging(CategorySlowAging.혈당조절);
177+
recipe4.setIngredientTags(new ArrayList<>());
178+
List<Recipe> allRecipes = List.of(recipe1, recipe2, recipe3, recipe4);
179+
180+
given(recipeRepository.findAll()).willReturn(allRecipes);
181+
182+
// when
183+
List<RecommendationResponseDTO> result = recommendationService.getRecommendationsForUser(member);
184+
185+
// then
186+
assertThat(result).hasSizeLessThanOrEqualTo(3);
187+
then(redisRecipeService).should().cacheRecommendations(eq(member.getId()), anyList(), eq(Duration.ofHours(1)));
188+
}
189+
190+
@Test
191+
@DisplayName("예외: 캐시 조회 후 결과가 null 이거나 비어있으면 빈 리스트 반환")
192+
void getRecommendedKeywords_ReturnsEmptyWhenCacheEmpty() {
193+
// given
194+
given(redisRecipeService.getCachedRecommendations(member.getId())).willReturn(null);
195+
196+
// when
197+
List<String> keywords = recommendationService.getRecommendedKeywords(member);
198+
199+
// then
200+
assertThat(keywords).isEmpty();
201+
}
202+
}
203+
204+
205+
@Nested
206+
@DisplayName("추천 검색어 조회 테스트")
207+
class GetRecommendedKeywordsTests {
208+
209+
@Test
210+
@DisplayName("성공: 캐시된 추천 결과가 있고, 키워드 및 식재료 이름 포함 반환")
211+
void returnsKeywordsFromCachedRecommendations() {
212+
// given
213+
RecommendationResponseDTO dto = Mockito.mock(RecommendationResponseDTO.class);
214+
given(dto.getTitle()).willReturn("감자조림은 맛있다");
215+
given(dto.getIngredientTagIds()).willReturn(List.of(1L, 2L));
216+
217+
given(redisRecipeService.getCachedRecommendations(member.getId()))
218+
.willReturn(List.of(dto));
219+
220+
Ingredient ing1 = new Ingredient();
221+
ing1.setName("감자");
222+
Ingredient ing2 = new Ingredient();
223+
ing2.setName("고추");
224+
225+
given(ingredientRepository.findByIdIn(List.of(1L, 2L))).willReturn(List.of(ing1, ing2));
226+
227+
// when
228+
List<String> keywords = recommendationService.getRecommendedKeywords(member);
229+
230+
// then
231+
assertThat(keywords).contains("감자조림", "맛있다", "감자", "고추");
232+
assertThat(keywords.size()).isLessThanOrEqualTo(5);
233+
}
234+
}
235+
236+
}

0 commit comments

Comments
 (0)