diff --git a/README.md b/README.md index 303a3b5..25b70fc 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,19 @@ -# Be +# ๐ŸŒฟ Leafy - ๊ธฐํ›„๋ฅผ ์ง€ํ‚ค๋Š” ์˜ค๋Š˜์˜ ์‹ค์ฒœ +**Leafy(๋ฆฌํ”ผ)** ๋Š” ์ผ์ƒ ์† ์ž‘์€ ์‹ค์ฒœ์„ ํ†ตํ•ด +๊ธฐํ›„ ๋ณ€ํ™”์— ๋Œ€์‘ํ•  ์ˆ˜ ์žˆ๋„๋ก ๋™๊ธฐ๋ฅผ ๋ถ€์—ฌํ•˜๋Š” ์‹ค์ฒœ ๊ธฐ๋ฐ˜ ํ”Œ๋žซํผ์ž…๋‹ˆ๋‹ค. +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0001](https://github.com/user-attachments/assets/c4203777-15ac-4aee-9199-835d336cc198) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0004](https://github.com/user-attachments/assets/8e6398cd-86a5-4abc-9fda-5bcf405e2f6d) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0003](https://github.com/user-attachments/assets/2657f0ff-2929-4b7c-a79a-6b8967af47c5) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0005](https://github.com/user-attachments/assets/3b32b9d2-e605-4f39-88b9-0d7b71b77b25) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0007](https://github.com/user-attachments/assets/6f813687-357d-46f9-b060-47506279dbea) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0017](https://github.com/user-attachments/assets/db4488ad-b1e1-417e-b93f-e7fa03bc0ea8) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0008](https://github.com/user-attachments/assets/5f8d118a-5320-4219-ab30-4d4f532ddc01) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0009](https://github.com/user-attachments/assets/8882bff1-4cb5-435c-a3fb-39ec2858ed53) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0010](https://github.com/user-attachments/assets/ee6a2833-be60-470a-ba33-869e15cd1eda) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0011](https://github.com/user-attachments/assets/71451d9e-aaef-4bc4-ba9d-8c3649e2a6d4) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0012](https://github.com/user-attachments/assets/eb221d99-f66a-42cb-bc2c-e5a3518c718c) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0014](https://github.com/user-attachments/assets/facd94c8-33ac-4b0b-9d89-d22a9fcb3926) +![8th Ne(o)rdinary Hackathon_Aแ„Œแ…ฉ_Leafy (1)_page-0016](https://github.com/user-attachments/assets/6fe23d15-d4e0-48e5-9473-05d69e6bf236) -### ์•„ํ‚คํ…์ฒ˜ -image diff --git a/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java b/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java index 37a5d9a..393b7f9 100644 --- a/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java +++ b/src/main/java/com/example/hackathon/domain/productpurchasehistory/facade/ProductPurchaseFacade.java @@ -56,6 +56,6 @@ public void purchase(Long userId, ProductPurchaseRequestDto request) { productPurchaseHistoryService.purchase(history); -// pointService.usingPoint(); + pointService.updatePointBalance(userId, product.price()); } } diff --git a/src/test/java/com/example/hackathon/domain/activity/service/ActivityServiceTest.java b/src/test/java/com/example/hackathon/domain/activity/service/ActivityServiceTest.java index 5b756b0..33e9293 100644 --- a/src/test/java/com/example/hackathon/domain/activity/service/ActivityServiceTest.java +++ b/src/test/java/com/example/hackathon/domain/activity/service/ActivityServiceTest.java @@ -1,10 +1,13 @@ package com.example.hackathon.domain.activity.service; -import com.example.hackathon.domain.point.dto.PointRequestDTO; -import com.example.hackathon.domain.point.entity.Point; -import com.example.hackathon.domain.point.entity.ProductType; -import com.example.hackathon.domain.point.repository.PointRepository; -import com.example.hackathon.domain.point.service.PointService; +import com.example.hackathon.domain.activity.dto.ActivityNewRequestDto; +import com.example.hackathon.domain.activity.dto.ActivityResponseDto; +import com.example.hackathon.domain.activity.entity.Activity; +import com.example.hackathon.domain.activity.entity.RepeatCycle; +import com.example.hackathon.domain.activity.repository.ActivityRepository; +import com.example.hackathon.domain.category.entity.Category; +import com.example.hackathon.domain.category.entity.CategoryType; +import com.example.hackathon.domain.category.repository.CategoryRepository; import com.example.hackathon.domain.user.entity.User; import com.example.hackathon.domain.user.repository.UserRepository; import com.example.hackathon.global.exception.BusinessException; @@ -15,6 +18,8 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; +import java.util.Arrays; +import java.util.List; import java.util.Optional; import static org.assertj.core.api.Assertions.*; @@ -25,103 +30,143 @@ import org.mockito.junit.jupiter.MockitoExtension; @ExtendWith(MockitoExtension.class) -class PointServiceTest { +class ActivityServiceTest { - @Mock - private PointRepository pointRepository; - - @Mock - private UserRepository userRepository; + @Mock private ActivityRepository activityRepository; + @Mock private UserRepository userRepository; + @Mock private CategoryRepository categoryRepository; @InjectMocks - private PointService pointService; + private ActivityService activityService; + + private Activity mockActivity; + + @BeforeEach + void setup() { + mockActivity = Activity.builder() + .id(1L) + .description("Test activity") + .point(100) + .sortOrder(1) + .isCustom(false) + .build(); + } - @Mock - private User user; + @Test + @DisplayName("์นดํ…Œ๊ณ ๋ฆฌ๋ณ„ ํ™œ๋™ ์กฐํšŒ ์„ฑ๊ณต") + void getActivitiesByCategoryWithTodayFlags_success() { + // given + when(activityRepository.findByCategoryIdAndIsDisplayedTrueOrderBySortOrderAsc(1L)) + .thenReturn(List.of(mockActivity)); - private Point mockPoint; + List todayIds = List.of(1L); - Long userId = 1L; + // when + List result = activityService.getActivitiesByCategoryWithTodayFlags(1L, todayIds); - @BeforeEach - void setUp() { - mockPoint = new Point(); - mockPoint.setUser(user); - mockPoint.setTotalPoint(500); + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).isTodayActivity()).isTrue(); + } + + @Test + @DisplayName("์˜ค๋Š˜์˜ ๋ฏธ์…˜ ํ™œ๋™ ์กฐํšŒ ์„ฑ๊ณต") + void getTodayMissionActivitiesWithTodayFlags_success() { + // given + when(activityRepository.findByIsDisplayedTrueAndIsTodayActivityTrueOrderBySortOrderAsc()) + .thenReturn(List.of(mockActivity)); + + List todayIds = List.of(1L); + + // when + List result = activityService.getTodayMissionActivitiesWithTodayFlags(todayIds); + + // then + assertThat(result).hasSize(1); + assertThat(result.get(0).isTodayActivity()).isTrue(); } @Test - @DisplayName("์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์กฐํšŒ - ์„ฑ๊ณต (500 ํฌ์ธํŠธ)") - void getUserTotalPoint_success() { + @DisplayName("๋‹จ์ผ ํ™œ๋™ ์กฐํšŒ - ์กด์žฌํ•  ๊ฒฝ์šฐ") + void getActivity_exists() { // given - when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + when(activityRepository.findById(1L)).thenReturn(Optional.of(mockActivity)); // when - int totalPoint = pointService.getUserTotalPoint(userId); + ActivityResponseDto result = activityService.getActivity(1L); // then - assertThat(totalPoint).isEqualTo(500); + assertThat(result).isNotNull(); + assertThat(result.getId()).isEqualTo(1L); } @Test - @DisplayName("์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์กฐํšŒ - ์ •๋ณด ์—†์„ ๊ฒฝ์šฐ 0 ๋ฐ˜ํ™˜") - void getUserTotalPoint_zeroWhenNotExists() { + @DisplayName("๋‹จ์ผ ํ™œ๋™ ์กฐํšŒ - ์กด์žฌํ•˜์ง€ ์•Š์„ ๊ฒฝ์šฐ null ๋ฐ˜ํ™˜") + void getActivity_notExists() { // given - when(pointRepository.findByUserId(userId)).thenReturn(Optional.empty()); + when(activityRepository.findById(1L)).thenReturn(Optional.empty()); // when - int totalPoint = pointService.getUserTotalPoint(userId); + ActivityResponseDto result = activityService.getActivity(1L); // then - assertThat(totalPoint).isEqualTo(0); + assertThat(result).isNull(); } @Test - @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์„ฑ๊ณต") - void usingPoint_success() { + @DisplayName("์‚ฌ์šฉ์ž ํ™œ๋™ ์ถ”๊ฐ€ ์„ฑ๊ณต") + void addUserActivities_success() { // given - PointRequestDTO.buyProductReq req = PointRequestDTO.buyProductReq.builder() - .productType(ProductType.KEYRING) // ์˜ˆ: KEYRING์€ 200ํฌ์ธํŠธ ํ•„์š” + User user = mock(User.class); + Category category = mock(Category.class); + ActivityNewRequestDto.AddActivity req = ActivityNewRequestDto.AddActivity.builder() + .categoryType(CategoryType.CONSUMPTION) + .description("์„ค๋ช…") + .title("์ œ๋ชฉ") + .repeatCycle(RepeatCycle.DAILY) .build(); - when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + when(userRepository.findByKakaoId(1L)).thenReturn(Optional.of(user)); + when(categoryRepository.findByCategoryType(CategoryType.CONSUMPTION)).thenReturn(Optional.of(category)); // when - pointService.usingPoint(userId, req); + activityService.addUserActivities(1L, req); // then - assertThat(mockPoint.getTotalPoint()).isEqualTo(279); // 500 - 200 + verify(activityRepository, times(1)).save(any(Activity.class)); } @Test - @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์ž”์—ฌ ํฌ์ธํŠธ ๋ถ€์กฑ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") - void usingPoint_notEnoughPoint_throwsException() { + @DisplayName("์‚ฌ์šฉ์ž ํ™œ๋™ ์ถ”๊ฐ€ - ์‚ฌ์šฉ์ž ์—†์Œ ์˜ˆ์™ธ") + void addUserActivities_userNotFound() { // given - PointRequestDTO.buyProductReq req = PointRequestDTO.buyProductReq.builder() - .productType(ProductType.KEYRING) // ์˜ˆ: ํ‚ค๋ง + ActivityNewRequestDto.AddActivity req = ActivityNewRequestDto.AddActivity.builder() + .categoryType(CategoryType.CONSUMPTION) .build(); - when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + when(userRepository.findByKakaoId(1L)).thenReturn(Optional.empty()); // expect - assertThatThrownBy(() -> pointService.usingPoint(userId, req)) + assertThatThrownBy(() -> activityService.addUserActivities(1L, req)) .isInstanceOf(BusinessException.class) - .hasMessageContaining(Code.POINT_NOT_ENOUGH.getMessage()); + .hasMessageContaining(Code.USER_NOT_FOUND.getMessage()); } @Test - @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์ •๋ณด๊ฐ€ ์—†์„ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") - void usingPoint_pointEntityNotFound_throwsException() { + @DisplayName("์‚ฌ์šฉ์ž ํ™œ๋™ ์ถ”๊ฐ€ - ์นดํ…Œ๊ณ ๋ฆฌ ์—†์Œ ์˜ˆ์™ธ") + void addUserActivities_categoryNotFound() { // given - PointRequestDTO.buyProductReq req = PointRequestDTO.buyProductReq.builder() - .productType(ProductType.KEYRING) + User user = mock(User.class); + ActivityNewRequestDto.AddActivity req = ActivityNewRequestDto.AddActivity.builder() + .categoryType(CategoryType.CONSUMPTION) .build(); - when(pointRepository.findByUserId(userId)).thenReturn(Optional.empty()); + when(userRepository.findByKakaoId(1L)).thenReturn(Optional.of(user)); + when(categoryRepository.findByCategoryType(CategoryType.CONSUMPTION)).thenReturn(Optional.empty()); // expect - assertThatThrownBy(() -> pointService.usingPoint(userId, req)) + assertThatThrownBy(() -> activityService.addUserActivities(1L, req)) .isInstanceOf(BusinessException.class) - .hasMessageContaining(Code.POINT_NOT_FOUND.getMessage()); + .hasMessageContaining(Code.CATEGORY_NOT_FOUND.getMessage()); } } diff --git a/src/test/java/com/example/hackathon/domain/point/service/PointServiceV1Test.java b/src/test/java/com/example/hackathon/domain/point/service/PointServiceV1Test.java new file mode 100644 index 0000000..37fb063 --- /dev/null +++ b/src/test/java/com/example/hackathon/domain/point/service/PointServiceV1Test.java @@ -0,0 +1,114 @@ +package com.example.hackathon.domain.point.service; + +import com.example.hackathon.domain.point.dto.PointRequestDTO; +import com.example.hackathon.domain.point.entity.Point; +import com.example.hackathon.domain.point.entity.ProductType; +import com.example.hackathon.domain.point.repository.PointRepository; +import com.example.hackathon.domain.user.entity.User; +import com.example.hackathon.domain.user.repository.UserRepository; +import com.example.hackathon.global.exception.BusinessException; +import com.example.hackathon.global.response.Code; + +import org.junit.jupiter.api.BeforeEach; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.extension.ExtendWith; + +import java.util.Optional; + +import static org.assertj.core.api.Assertions.*; +import static org.mockito.Mockito.*; + +import org.mockito.InjectMocks; +import org.mockito.Mock; +import org.mockito.junit.jupiter.MockitoExtension; + +@ExtendWith(MockitoExtension.class) +class PointServiceV1Test { + + @Mock + private PointRepository pointRepository; + + @Mock + private UserRepository userRepository; + + @InjectMocks + private PointService pointService; + + @Mock + private User user; + + private Point mockPoint; + + Long userId = 1L; + + @BeforeEach + void setUp() { + mockPoint = new Point(); + mockPoint.setUser(user); + mockPoint.setTotalPoint(500); + } + + @Test + @DisplayName("์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์กฐํšŒ - ์„ฑ๊ณต (500 ํฌ์ธํŠธ)") + void getUserTotalPoint_success() { + // given + when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + + // when + int totalPoint = pointService.getUserTotalPoint(userId); + + // then + assertThat(totalPoint).isEqualTo(500); + } + + @Test + @DisplayName("์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์กฐํšŒ - ์ •๋ณด ์—†์„ ๊ฒฝ์šฐ 0 ๋ฐ˜ํ™˜") + void getUserTotalPoint_zeroWhenNotExists() { + // given + when(pointRepository.findByUserId(userId)).thenReturn(Optional.empty()); + + // when + int totalPoint = pointService.getUserTotalPoint(userId); + + // then + assertThat(totalPoint).isEqualTo(0); + } + + @Test + @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์„ฑ๊ณต") + void usingPoint_success() { + // given + when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + + // when + pointService.updatePointBalance(userId, ProductType.KEYRING.getPoint()); + + // then + assertThat(mockPoint.getTotalPoint()).isEqualTo(279); // 500 - 200 + } + + @Test + @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์ž”์—ฌ ํฌ์ธํŠธ ๋ถ€์กฑ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void usingPoint_notEnoughPoint_throwsException() { + // given + when(pointRepository.findByUserId(userId)).thenReturn(Optional.of(mockPoint)); + + // expect + assertThatThrownBy(() -> pointService.updatePointBalance(userId, ProductType.KEYRING.getPoint())) + .isInstanceOf(BusinessException.class) + .hasMessageContaining(Code.POINT_NOT_ENOUGH.getMessage()); + } + + @Test + @DisplayName("ํฌ์ธํŠธ ์‚ฌ์šฉ - ์‚ฌ์šฉ์ž ํฌ์ธํŠธ ์ •๋ณด๊ฐ€ ์—†์„ ์‹œ ์˜ˆ์™ธ ๋ฐœ์ƒ") + void usingPoint_pointEntityNotFound_throwsException() { + // given + when(pointRepository.findByUserId(userId)).thenReturn(Optional.empty()); + + // expect + assertThatThrownBy(() -> pointService.updatePointBalance(userId, ProductType.KEYRING.getPoint())) + .isInstanceOf(BusinessException.class) + .hasMessageContaining(Code.POINT_NOT_FOUND.getMessage()); + } +}