diff --git a/application/src/main/java/com/groom/yummy/controller/GroupController.java b/application/src/main/java/com/groom/yummy/controller/GroupController.java index 2d94697..275c2ca 100755 --- a/application/src/main/java/com/groom/yummy/controller/GroupController.java +++ b/application/src/main/java/com/groom/yummy/controller/GroupController.java @@ -6,14 +6,14 @@ import com.groom.yummy.group.dto.request.JoinGroupRequestDto; import com.groom.yummy.group.dto.response.GroupDetailResponseDto; import com.groom.yummy.group.dto.response.GroupResponseDto; +import com.groom.yummy.oauth2.auth.LoginUser; import io.swagger.v3.oas.annotations.Operation; import io.swagger.v3.oas.annotations.tags.Tag; import jakarta.validation.Valid; import lombok.RequiredArgsConstructor; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; -import org.springframework.security.core.Authentication; -import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.core.annotation.AuthenticationPrincipal; import org.springframework.web.bind.annotation.*; import java.util.List; @@ -30,15 +30,23 @@ public class GroupController { @Operation(summary = "소모임 생성", description = "소모임을 생성합니다.") @PostMapping public ResponseEntity> createGroup( - @Valid @RequestBody CreateGroupRequestDto requestDto + @Valid @RequestBody CreateGroupRequestDto requestDto, + @AuthenticationPrincipal LoginUser loginUser ) { - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String userEmail = authentication.getName(); + Long userId = loginUser.getUserId(); + Long groupId = groupService.createGroup( + requestDto.getStoreId(), + userId, + requestDto.getTitle(), + requestDto.getContent(), + requestDto.getMaxParticipants(), + requestDto.getMinParticipants(), + requestDto.getMeetingDate() + ); - Long groupId = groupService.createGroup(requestDto.toGroupDomain(), userEmail); GroupResponseDto response = groupService.findGroupById(groupId) .map(GroupResponseDto::fromGroupDomain) - .orElseThrow(() -> new IllegalArgumentException("소모임 생성 실패")); + .orElseThrow(); return ResponseEntity.status(HttpStatus.CREATED) .body(new ResponseDto<>(response, "소모임 생성 성공")); @@ -76,13 +84,11 @@ public ResponseEntity> getGroupById( @PostMapping("/{groupId}/join") public ResponseEntity> joinGroup( @PathVariable Long groupId, - @Valid @RequestBody JoinGroupRequestDto request + @Valid @RequestBody JoinGroupRequestDto requestDto, + @AuthenticationPrincipal LoginUser loginUser ) { - - Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); - String userEmail = authentication.getName(); - - groupService.joinGroup(groupId, request.getUserId(), userEmail); + Long userId = loginUser.getUserId(); + groupService.joinGroup(groupId, userId, requestDto.getStoreId()); return ResponseEntity.ok(new ResponseDto<>(null, "소모임 참여 성공")); } } diff --git a/application/src/main/java/com/groom/yummy/controller/StoreController.java b/application/src/main/java/com/groom/yummy/controller/StoreController.java index 218b560..ea2fc07 100644 --- a/application/src/main/java/com/groom/yummy/controller/StoreController.java +++ b/application/src/main/java/com/groom/yummy/controller/StoreController.java @@ -48,24 +48,6 @@ public ResponseEntity> syncStores(@RequestParam String regionC .body(new ResponseDto<>(null, "가게 데이터 동기화 중 오류 발생")); } } - @Operation(summary = "가게 정보 조회", description = "가게 id로 가게를 조회합니다.") - @GetMapping("/{storeId}") - public ResponseEntity> getStore(@PathVariable("storeId") Long storeId) { - StoreResponseDto storeResponseDTO = storeApiClient.getStoreByApi(storeId); - return ResponseEntity.ok(ResponseDto.of(storeResponseDTO,"storeId로 가게 조회 성공")); - } - - @Operation(summary = "가게 조회", description = "가게들을 정렬 기준에 맞게 조회합니다.") - @GetMapping - public ResponseEntity> getStoresByFilters( - @RequestParam(name = "category", required = false) Category category, - @RequestParam(name = "regionId", required = false) Long regionId, - @RequestParam(name = "name", required = false) String name, - @RequestParam(name = "page", defaultValue = "1") int page, - @RequestParam(name = "size", defaultValue = "10") int size) { - ApiResponse storeListResponseApiResponse = storeApiClient.getStoresByFilters(category, regionId,name,page,size); - return ResponseEntity.ok(storeListResponseApiResponse); - } } diff --git a/application/src/test/java/com/groom/yummy/controller/GroupControllerTest.java b/application/src/test/java/com/groom/yummy/controller/GroupControllerTest.java index 100f2c7..30ce8a4 100755 --- a/application/src/test/java/com/groom/yummy/controller/GroupControllerTest.java +++ b/application/src/test/java/com/groom/yummy/controller/GroupControllerTest.java @@ -7,33 +7,36 @@ import com.groom.yummy.group.dto.request.CreateGroupRequestDto; import com.groom.yummy.group.dto.request.JoinGroupRequestDto; import com.groom.yummy.group.dto.response.GroupDetailResponseDto; -import com.groom.yummy.group.dto.response.GroupResponseDto; import com.groom.yummy.jwt.JwtProvider; +import com.groom.yummy.oauth2.auth.LoginUser; +import com.groom.yummy.user.User; import jakarta.servlet.http.Cookie; +import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Order; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.http.MediaType; -import org.springframework.security.test.context.support.WithMockUser; +import org.springframework.security.authentication.UsernamePasswordAuthenticationToken; +import org.springframework.security.core.context.SecurityContextHolder; +import org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors; import org.springframework.test.context.bean.override.mockito.MockitoBean; import org.springframework.test.web.servlet.MockMvc; +import org.springframework.test.web.servlet.ResultActions; import java.time.LocalDateTime; import java.util.List; import java.util.Optional; import static org.mockito.ArgumentMatchers.any; -import static org.mockito.Mockito.when; +import static org.mockito.Mockito.*; import static org.springframework.security.test.web.servlet.request.SecurityMockMvcRequestPostProcessors.csrf; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; -import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; -import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; +import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; +import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*; @WebMvcTest(GroupController.class) -public class GroupControllerTest { +class GroupControllerTest { @Autowired private MockMvc mockMvc; @@ -47,67 +50,97 @@ public class GroupControllerTest { @MockitoBean private JwtProvider jwtProvider; - @DisplayName("사용자는 소모임을 생성할 수 있다.") - @Test - @Order(1) - @WithMockUser(username = "testUser@gmail.com", roles = "USER") - void 그룹_생성_테스트() throws Exception { - // Given - CreateGroupRequestDto createGroupRequestDto = CreateGroupRequestDto.builder() - .title("Go to Goorm Store!") - .content("yummy yummy yummy yummy yummy") - .maxParticipants(4) - .minParticipants(3) - .meetingDate(LocalDateTime.now()) - .storeId(10L) - .build(); + private Cookie authCookie; - GroupResponseDto groupResponseDto = GroupResponseDto.builder() + @BeforeEach + void setUp() { + // Mock User 객체 생성 + User mockUser = User.builder() .id(1L) - .title("Go to Goorm Store!") - .content("yummy yummy yummy yummy") - .maxParticipants(4) - .minParticipants(3) - .currentParticipants(1) - .meetingDate(LocalDateTime.now()) - .meetingStatus("OPEN") - .storeId(10L) - .createdAt(LocalDateTime.now()) + .email("testUser@gmail.com") + .nickname("testNickname") + .role("USER") .build(); - // Mock JwtProvider 동작 정의 + // Mock LoginUser 생성 + LoginUser mockLoginUser = new LoginUser(mockUser); + + // 인증 객체 생성 + SecurityContextHolder.getContext().setAuthentication( + new UsernamePasswordAuthenticationToken(mockLoginUser, null, List.of()) + ); + + // JWT 검증 when(jwtProvider.validateToken("valid.jwt.token")).thenReturn(true); when(jwtProvider.getUsername("valid.jwt.token")).thenReturn("testUser@gmail.com"); - when(groupService.createGroup(any(Group.class), any(String.class))).thenReturn(1L); - when(groupService.findGroupById(1L)).thenReturn(Optional.of(Group.builder() - .id(1L) + // Authorization 쿠키 생성 + authCookie = new Cookie("Authorization", "valid.jwt.token"); + } + + @Test + @Order(1) + @DisplayName("사용자는 소모임을 생성할 수 있다.") + void 소모임_생성_테스트() throws Exception { + // given + CreateGroupRequestDto requestDto = CreateGroupRequestDto.builder() .title("Go to Goorm Store!") .content("yummy yummy yummy yummy") .maxParticipants(4) .minParticipants(3) + .meetingDate(LocalDateTime.now()) .storeId(10L) + .build(); + + // Mock groupId 반환값 + Long mockGroupId = 1L; + + // Mock 그룹 생성 동작 + when(groupService.createGroup(any(), any(), any(), any(), any(), any(), any())) + .thenReturn(mockGroupId); + + // Mock findGroupById 반환값 설정 + Group mockGroup = Group.builder() + .id(mockGroupId) + .title(requestDto.getTitle()) + .content(requestDto.getContent()) + .maxParticipants(requestDto.getMaxParticipants()) + .minParticipants(requestDto.getMinParticipants()) + .currentParticipants(1) + .meetingDate(requestDto.getMeetingDate()) .meetingStatus(MeetingStatus.OPEN) - .build())); + .storeId(requestDto.getStoreId()) + .build(); - // When & Then - mockMvc.perform(post("/api/v1/groups") - .cookie(new Cookie("Authorization", "valid.jwt.token")) - .with(csrf()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(createGroupRequestDto))) - .andExpect(status().isCreated()) - .andExpect(jsonPath("$.msg").value("소모임 생성 성공")) - .andExpect(jsonPath("$.data.id").value(1L)) - .andExpect(jsonPath("$.data.title").value("Go to Goorm Store!")); + when(groupService.findGroupById(mockGroupId)).thenReturn(Optional.of(mockGroup)); + + String body = objectMapper.writeValueAsString(requestDto); + + // when + ResultActions actions = mockMvc.perform(post("/api/v1/groups") + .cookie(authCookie) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(body)); + + // then + actions.andExpectAll( + status().isCreated(), + jsonPath("$.msg").value("소모임 생성 성공"), + jsonPath("$.data.id").value(1L) + ); + + // 호출 횟수 검증 + verify(groupService, times(1)).createGroup(any(), any(), any(), any(), any(), any(), any()); + verify(groupService, times(1)).findGroupById(mockGroupId); } - @DisplayName("사용자는 소모임 목록을 조회할 수 있다.") + @Test @Order(2) - @WithMockUser(username = "TestUser@gmail.com", roles = "USER") - void 소모임_목록_리스트_조회_테스트() throws Exception { - // Given + @DisplayName("사용자는 소모임 목록을 조회할 수 있다.") + void 소모임_리스트_조회_테스트() throws Exception { + // given Group group = Group.builder() .id(1L) .title("Go to Goorm Store!") @@ -120,30 +153,34 @@ public class GroupControllerTest { .storeId(10L) .build(); - when(groupService.getAllGroups(any(String.class), any(String.class), any(String.class), any(int.class))) + when(groupService.getAllGroups(any(), any(), any(), anyInt())) .thenReturn(List.of(group)); - // When & Then - mockMvc.perform(get("/api/v1/groups") - .param("category", "KOREAN") - .param("regionCode", "110110110") - .param("storeName", "구룸식당") - .param("page", "1") - .cookie(new Cookie("Authorization", "valid.jwt.token"))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.msg").value("소모임 목록 조회 성공")) - .andExpect(jsonPath("$.data[0].id").value(1L)) - .andExpect(jsonPath("$.data[0].title").value("Go to Goorm Store!")); + // when + ResultActions actions = mockMvc.perform(get("/api/v1/groups") + .param("category", "KOREAN") + .param("regionCode", "110110110") + .param("storeName", "구룸식당") + .param("page", "1") + .cookie(authCookie)); + + // then + actions.andExpectAll( + status().isOk(), + jsonPath("$.msg").value("소모임 목록 조회 성공"), + jsonPath("$.data[0].id").value(1L), + jsonPath("$.data[0].title").value("Go to Goorm Store!") + ); + + verify(groupService, times(1)).getAllGroups(any(), any(), any(), anyInt()); } - - @DisplayName("사용자는 소모임 상세 정보를 조회할 수 있다.") @Test @Order(3) - @WithMockUser(username = "testUser@gmail.com", roles = "USER") - void 소모임_상세_조회_테스트() throws Exception { - // Given - GroupDetailResponseDto groupDetailResponseDto = GroupDetailResponseDto.builder() + @DisplayName("사용자는 소모임 상세 정보를 조회할 수 있다.") + void 소모임_상세정보_조회_테스트() throws Exception { + // given + GroupDetailResponseDto responseDto = GroupDetailResponseDto.builder() .id(1L) .title("Go to Goorm Store!") .content("yummy yummy yummy yummy") @@ -168,36 +205,51 @@ public class GroupControllerTest { .storeId(10L) .build())); - // When & Then - mockMvc.perform(get("/api/v1/groups/{groupId}", 1L) - .cookie(new Cookie("Authorization", "valid.jwt.token"))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.msg").value("소모임 상세 정보 조회 성공")) - .andExpect(jsonPath("$.data.id").value(1L)) - .andExpect(jsonPath("$.data.title").value("Go to Goorm Store!")); + // when + ResultActions actions = mockMvc.perform(get("/api/v1/groups/{groupId}", 1L) + .cookie(authCookie)); + + // then + actions.andExpectAll( + status().isOk(), + jsonPath("$.msg").value("소모임 상세 정보 조회 성공"), + jsonPath("$.data.id").value(1L), + jsonPath("$.data.title").value("Go to Goorm Store!") + ); + + verify(groupService, times(1)).findGroupById(1L); } - @DisplayName("사용자는 소모임에 참여할 수 있다.") @Test @Order(4) - @WithMockUser(username = "testUser@gmail.com", roles = "USER") - void 소모임_참가_테스트() throws Exception { - // Given - JoinGroupRequestDto joinGroupRequestDto = JoinGroupRequestDto.builder() + @DisplayName("사용자는 소모임에 참여할 수 있다.") + void 소모임_가입_테스트() throws Exception { + // given + Long groupId = 1L; + Long storeId = 10L; + + JoinGroupRequestDto joinRequestDto = JoinGroupRequestDto.builder() .userId(1L) + .storeId(storeId) .build(); - // Mocking JwtProvider 동작 정의 - when(jwtProvider.validateToken("valid.jwt.token")).thenReturn(true); - when(jwtProvider.getUsername("valid.jwt.token")).thenReturn("testUser@gmail.com"); + doNothing().when(groupService).joinGroup(eq(groupId), any(), eq(storeId)); + + String body = objectMapper.writeValueAsString(joinRequestDto); + + // when + ResultActions actions = mockMvc.perform(post("/api/v1/groups/{groupId}/join", groupId) + .cookie(authCookie) + .with(csrf()) + .contentType(MediaType.APPLICATION_JSON) + .content(body)); + + // then + actions.andExpectAll( + status().isOk(), + jsonPath("$.msg").value("소모임 참여 성공") + ); - // When & Then - mockMvc.perform(post("/api/v1/groups/{groupId}/join", 1L) - .cookie(new Cookie("Authorization", "valid.jwt.token")) - .with(csrf()) - .contentType(MediaType.APPLICATION_JSON) - .content(objectMapper.writeValueAsString(joinGroupRequestDto))) - .andExpect(status().isOk()) - .andExpect(jsonPath("$.msg").value("소모임 참여 성공")); + verify(groupService, times(1)).joinGroup(eq(groupId), any(), eq(storeId)); } } diff --git a/domain/src/main/java/com/groom/yummy/exception/GroupErrorCode.java b/domain/src/main/java/com/groom/yummy/exception/GroupErrorCode.java index aacff3b..c2c2027 100644 --- a/domain/src/main/java/com/groom/yummy/exception/GroupErrorCode.java +++ b/domain/src/main/java/com/groom/yummy/exception/GroupErrorCode.java @@ -6,7 +6,8 @@ @Getter public enum GroupErrorCode implements ErrorCode{ GROUP_NOT_FOUND(HttpStatus.NOT_FOUND, "그룹이 존재하지 않습니다."), - GROUP_PARTICIPATION_FULL(HttpStatus.NOT_FOUND, "참가 인원이 가득 찼습니다.") + GROUP_PARTICIPATION_FULL(HttpStatus.NOT_FOUND, "참가 인원이 가득 찼습니다."), + GROUP_CREATE_FAILED(HttpStatus.NOT_FOUND, "그룹 생성이 실패했습니다.") ; private final HttpStatus code; private final String message; diff --git a/domain/src/main/java/com/groom/yummy/group/GroupService.java b/domain/src/main/java/com/groom/yummy/group/GroupService.java index 3727e7a..340620e 100755 --- a/domain/src/main/java/com/groom/yummy/group/GroupService.java +++ b/domain/src/main/java/com/groom/yummy/group/GroupService.java @@ -4,13 +4,17 @@ import com.groom.yummy.exception.GroupErrorCode; import com.groom.yummy.exception.StoreErrorCode; import com.groom.yummy.exception.UserErrorCode; +import com.groom.yummy.store.Store; +import com.groom.yummy.store.StoreRepository; import com.groom.yummy.user.User; import com.groom.yummy.user.UserRepository; import com.groom.yummy.usertogroup.AttendanceStatus; +import com.groom.yummy.usertogroup.UserToGroup; import com.groom.yummy.usertogroup.UserToGroupRepository; import lombok.RequiredArgsConstructor; import org.springframework.stereotype.Service; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -21,18 +25,36 @@ public class GroupService { private final GroupRepository groupRepository; private final UserRepository userRepository; private final UserToGroupRepository userToGroupRepository; + private final StoreRepository storeRepository; - public Long createGroup(Group group, String userEmail) { - User user = userRepository.findByEmail(userEmail) + public Long createGroup(Long storeId, Long userId, String title, String content, Integer maxParticipants, Integer minParticipants, LocalDateTime meetingDate) { + User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); - Long storeId = group.getStoreId(); if (storeId == null) { throw new CustomException(StoreErrorCode.STORE_NOT_FOUND); } - return groupRepository.saveGroup(group, storeId); + + Group group = Group.builder() + .title(title) + .content(content) + .maxParticipants(maxParticipants) + .minParticipants(minParticipants) + .currentParticipants(1) + .meetingDate(meetingDate) + .meetingStatus(MeetingStatus.OPEN) + .storeId(storeId) + .build(); + + try { + userToGroupRepository.saveUserToGroup(group, user, null, true, AttendanceStatus.APPROVED); + return groupRepository.saveGroup(group, storeId); + } catch (Exception e) { + throw new CustomException(GroupErrorCode.GROUP_CREATE_FAILED); + } } + public Optional findGroupById(Long id) { return groupRepository.findGroupById(id); } @@ -41,19 +63,22 @@ public List getAllGroups(String category, String regionCode, String store return groupRepository.findAllGroups(category, regionCode, storeName, page); } - public void joinGroup(Long groupId, Long userId, String userEmail) { - User user = userRepository.findByEmail(userEmail) + public void joinGroup(Long groupId, Long userId, Long storeId) { + User user = userRepository.findById(userId) .orElseThrow(() -> new CustomException(UserErrorCode.USER_NOT_FOUND)); Group group = groupRepository.findGroupById(groupId) .orElseThrow(() -> new CustomException(GroupErrorCode.GROUP_NOT_FOUND)); + Store store = storeRepository.findStoreById(storeId) + .orElseThrow(() -> new CustomException(StoreErrorCode.STORE_NOT_FOUND)); + if (group.getCurrentParticipants() >= group.getMaxParticipants()) { throw new CustomException(GroupErrorCode.GROUP_PARTICIPATION_FULL); } groupRepository.updateGroupParticipants(groupId, group.getCurrentParticipants() + 1); - userToGroupRepository.save(group, user, false, AttendanceStatus.APPROVED); + userToGroupRepository.saveUserToGroup(group, user, store, false, AttendanceStatus.APPROVED); } } diff --git a/domain/src/main/java/com/groom/yummy/group/dto/request/CreateGroupRequestDto.java b/domain/src/main/java/com/groom/yummy/group/dto/request/CreateGroupRequestDto.java index 60f49bf..48fd68d 100755 --- a/domain/src/main/java/com/groom/yummy/group/dto/request/CreateGroupRequestDto.java +++ b/domain/src/main/java/com/groom/yummy/group/dto/request/CreateGroupRequestDto.java @@ -11,12 +11,13 @@ @AllArgsConstructor @Builder public class CreateGroupRequestDto { + private Long storeId; + private Long userId; private String title; private String content; private Integer maxParticipants; private Integer minParticipants; private LocalDateTime meetingDate; - private Long storeId; public Group toGroupDomain() { return Group.builder() @@ -24,7 +25,6 @@ public Group toGroupDomain() { .content(this.content) .maxParticipants(this.maxParticipants) .minParticipants(this.minParticipants) - .currentParticipants(1) .meetingDate(this.meetingDate) .storeId(this.storeId) .build(); diff --git a/domain/src/main/java/com/groom/yummy/group/dto/request/JoinGroupRequestDto.java b/domain/src/main/java/com/groom/yummy/group/dto/request/JoinGroupRequestDto.java index 950991e..44a7076 100755 --- a/domain/src/main/java/com/groom/yummy/group/dto/request/JoinGroupRequestDto.java +++ b/domain/src/main/java/com/groom/yummy/group/dto/request/JoinGroupRequestDto.java @@ -9,5 +9,6 @@ @Builder public class JoinGroupRequestDto { private Long userId; + private Long storeId; } diff --git a/domain/src/main/java/com/groom/yummy/usertogroup/UserToGroupRepository.java b/domain/src/main/java/com/groom/yummy/usertogroup/UserToGroupRepository.java index 229ac9c..751a09f 100644 --- a/domain/src/main/java/com/groom/yummy/usertogroup/UserToGroupRepository.java +++ b/domain/src/main/java/com/groom/yummy/usertogroup/UserToGroupRepository.java @@ -1,13 +1,13 @@ package com.groom.yummy.usertogroup; import com.groom.yummy.group.Group; +import com.groom.yummy.store.Store; import com.groom.yummy.user.User; import java.util.Optional; public interface UserToGroupRepository { - - void save(Group group, User user, boolean isLeader, AttendanceStatus attendanceStatus); - + void saveUserToGroup(Group group, User user, Store store, boolean isLeader, AttendanceStatus attendanceStatus); Optional findByGroupAndUser(Group group, User user); } + diff --git a/domain/src/test/java/com/groom/yummy/group/GroupServiceTest.java b/domain/src/test/java/com/groom/yummy/group/GroupServiceTest.java index 18c5694..d5d5969 100755 --- a/domain/src/test/java/com/groom/yummy/group/GroupServiceTest.java +++ b/domain/src/test/java/com/groom/yummy/group/GroupServiceTest.java @@ -1,6 +1,8 @@ package com.groom.yummy.group; import com.groom.yummy.exception.CustomException; +import com.groom.yummy.store.Store; +import com.groom.yummy.store.StoreRepository; import com.groom.yummy.user.User; import com.groom.yummy.user.UserRepository; import com.groom.yummy.usertogroup.AttendanceStatus; @@ -9,9 +11,9 @@ import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; -import org.mockito.Mockito; import org.mockito.junit.jupiter.MockitoExtension; +import java.time.LocalDateTime; import java.util.List; import java.util.Optional; @@ -36,48 +38,51 @@ public class GroupServiceTest { @Mock private UserToGroupRepository userToGroupRepository; - @DisplayName("사용자는 소모임을 생성할 수 있다.") + @Mock + private StoreRepository storeRepository; + + @DisplayName("User can create a group.") @Order(1) @Test - void 소모임_생성_테스트() { - //Given + void createGroupTest() { + // Given + Long storeId = 10L; + Long userId = 1L; + String title = "Go to Goorm store"; + String content = "yummy yummy yummy yummy yummy"; + Integer maxParticipants = 4; + Integer minParticipants = 3; + LocalDateTime meetingDate = LocalDateTime.now(); + User user = User.builder() - .id(1L) + .id(userId) .email("Goorm@gmail.com") .nickname("Goorm") .role("USER") - .groupJoinCount(10L) - .groupAttendanceCount(8L) .isDeleted(false) .build(); - Group group = Group.builder() - .title("Go to Goorm store") - .content("yummy yummy yummy yummy yummy") - .maxParticipants(4) - .minParticipants(3) - .storeId(10L) - .build(); - - when(userRepository.findByEmail(Mockito.eq("Goorm@gmail.com"))) + when(userRepository.findById(userId)) .thenReturn(Optional.of(user)); - - when(groupRepository.saveGroup(any(Group.class), anyLong())) + when(groupRepository.saveGroup(any(Group.class), eq(storeId))) .thenReturn(1L); // When - Long groupId = groupService.createGroup(group, user.getEmail()); + Long groupId = groupService.createGroup(storeId, userId, title, content, maxParticipants, minParticipants, meetingDate); // Then assertEquals(1L, groupId); verify(groupRepository, times(1)) - .saveGroup(any(Group.class), anyLong()); + .saveGroup(any(Group.class), eq(storeId)); + verify(userToGroupRepository, times(1)) + .saveUserToGroup(any(Group.class), eq(user), isNull(), eq(true), eq(AttendanceStatus.APPROVED)); } - @DisplayName("사용자는 소모임 상세 정보를 조회할 수 있다.") + + @DisplayName("User can view group details.") @Order(2) @Test - void 소모임_상세_조회_테스트() { + void viewGroupDetailsTest() { // Given Long groupId = 1L; Group group = Group.builder() @@ -101,14 +106,14 @@ public class GroupServiceTest { verify(groupRepository, times(1)).findGroupById(groupId); } - @DisplayName("사용자는 소모임에 참여할 수 있다.") + @DisplayName("User can join a group.") @Order(3) @Test - void 소모임_참여_테스트() { + void joinGroupTest() { // Given Long groupId = 1L; Long userId = 1L; - String userEmail = "Goorm@gmail.com"; + Long storeId = 10L; Group group = Group.builder() .id(groupId) @@ -117,77 +122,80 @@ public class GroupServiceTest { .maxParticipants(4) .minParticipants(3) .currentParticipants(2) - .storeId(10L) + .storeId(storeId) .build(); User user = User.builder() .id(userId) - .email(userEmail) + .email("Goorm@gmail.com") .nickname("Goorm") .role("USER") - .groupJoinCount(10L) - .groupAttendanceCount(8L) .isDeleted(false) .build(); - when(userRepository.findByEmail(userEmail)).thenReturn(Optional.of(user)); + Store store = new Store(); // Store 객체 생성 + + when(userRepository.findById(userId)).thenReturn(Optional.of(user)); when(groupRepository.findGroupById(groupId)).thenReturn(Optional.of(group)); + when(storeRepository.findStoreById(storeId)).thenReturn(Optional.of(store)); // Mock 동작 추가 + + // Mock UserToGroupRepository 동작 설정 + doNothing().when(userToGroupRepository) + .saveUserToGroup(eq(group), eq(user), eq(store), eq(false), eq(AttendanceStatus.APPROVED)); // When - groupService.joinGroup(groupId, userId, userEmail); + groupService.joinGroup(groupId, userId, storeId); // Then verify(groupRepository, times(1)).updateGroupParticipants(eq(groupId), eq(3)); verify(userToGroupRepository, times(1)) - .save(eq(group), eq(user), eq(false), eq(AttendanceStatus.APPROVED)); // save 호출 검증 + .saveUserToGroup(eq(group), eq(user), eq(store), eq(false), eq(AttendanceStatus.APPROVED)); } - - @DisplayName("소모임 참여 시 참가 인원이 초과되면 예외가 발생한다.") + @DisplayName("Group join fails when participant limit exceeded.") @Order(4) @Test - void 소모임_참여_참가인원_초과_테스트() { + void joinGroupParticipantLimitExceededTest() { // Given Long groupId = 1L; Long userId = 1L; - String userEmail = "Goorm@gmail.com"; + Long storeId = 10L; Group group = Group.builder() .id(groupId) .title("Go to Goorm store") .content("yummy yummy") .maxParticipants(4) - .minParticipants(3) - .currentParticipants(4) - .storeId(10L) + .currentParticipants(4) // 참여 인원 초과 + .storeId(storeId) .build(); User user = User.builder() .id(userId) - .email(userEmail) + .email("Goorm@gmail.com") .nickname("Goorm") - .role("USER") - .groupJoinCount(10L) - .groupAttendanceCount(8L) - .isDeleted(false) .build(); - when(userRepository.findByEmail(userEmail)).thenReturn(Optional.of(user)); + Store store = new Store(); // Store 객체 생성 + + when(userRepository.findById(userId)).thenReturn(Optional.of(user)); when(groupRepository.findGroupById(groupId)).thenReturn(Optional.of(group)); + when(storeRepository.findStoreById(storeId)).thenReturn(Optional.of(store)); // Mock 동작 추가 // When CustomException exception = assertThrows(CustomException.class, - () -> groupService.joinGroup(groupId, userId, userEmail)); + () -> groupService.joinGroup(groupId, userId, storeId)); // Then assertEquals("참가 인원이 가득 찼습니다.", exception.getMessage()); verify(groupRepository, never()).updateGroupParticipants(anyLong(), anyInt()); } - @DisplayName("소모임 리스트 조회 테스트") + + @DisplayName("Retrieve group list test.") @Order(5) @Test - void 소모임_리스트_조회_테스트() { + void retrieveGroupListTest() { // Given String category = "KOREAN"; String regionCode = "SEOUL"; @@ -200,7 +208,6 @@ public class GroupServiceTest { .title("Go to Goorm store") .content("yummy yummy") .maxParticipants(4) - .minParticipants(3) .currentParticipants(2) .storeId(10L) .build() diff --git a/storage/src/main/java/com/groom/yummy/domain/usertogroup/UserToGroupEntityRepository.java b/storage/src/main/java/com/groom/yummy/domain/usertogroup/UserToGroupEntityRepository.java index 2522a9e..e1bc453 100644 --- a/storage/src/main/java/com/groom/yummy/domain/usertogroup/UserToGroupEntityRepository.java +++ b/storage/src/main/java/com/groom/yummy/domain/usertogroup/UserToGroupEntityRepository.java @@ -1,13 +1,13 @@ package com.groom.yummy.domain.usertogroup; import com.groom.yummy.domain.group.GroupEntity; -import com.groom.yummy.domain.group.GroupJpaRepository; import com.groom.yummy.domain.store.StoreEntity; import com.groom.yummy.domain.store.StoreJpaRepository; import com.groom.yummy.domain.user.UserEntity; -import com.groom.yummy.usertogroup.AttendanceStatus; import com.groom.yummy.group.Group; +import com.groom.yummy.store.Store; import com.groom.yummy.user.User; +import com.groom.yummy.usertogroup.AttendanceStatus; import com.groom.yummy.usertogroup.UserToGroup; import com.groom.yummy.usertogroup.UserToGroupRepository; import lombok.RequiredArgsConstructor; @@ -23,7 +23,7 @@ public class UserToGroupEntityRepository implements UserToGroupRepository { private final StoreJpaRepository storeJpaRepository; @Override - public void save(Group group, User user, boolean isLeader, AttendanceStatus attendanceStatus) { + public void saveUserToGroup(Group group, User user, Store store, boolean isLeader, AttendanceStatus attendanceStatus) { StoreEntity storeEntity = group.getStoreId() != null ? storeJpaRepository.findById(group.getStoreId()) .orElseThrow(() -> new IllegalArgumentException("Store not found for id: " + group.getStoreId()))