-
Notifications
You must be signed in to change notification settings - Fork 0
[feat] 솜커톤 API GitHub & 포트폴리오 링크 추가 #105
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 6 commits
10e7189
0c2e084
2ec7fb6
ab66613
4a29327
af60e14
6e65595
5616eef
1052852
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -42,3 +42,7 @@ out/ | |
| ### dev ### | ||
| application-dev.yml | ||
|
|
||
| # local/dev only | ||
| .dev/ | ||
| docker-compose.yml | ||
| init-user.sql | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -7,6 +7,7 @@ | |
| import jakarta.validation.constraints.Size; | ||
| import lombok.Getter; | ||
| import lombok.Setter; | ||
| import org.hibernate.validator.constraints.URL; | ||
|
|
||
| @Getter | ||
| @Setter | ||
|
|
@@ -41,4 +42,14 @@ public class SomParticipantRequestDto { | |
| @Email(message = "올바른 이메일 형식이 아닙니다.") | ||
| @Schema(description = "이메일 주소", example = "[email protected]", required = true) | ||
| private String email; // 이메일 | ||
|
|
||
| @NotBlank(message = "GitHub 주소는 필수 입력 값입니다.") | ||
|
||
| @URL(protocol = "https", host = "github.com", message = "GitHub URL이 올바르지 않습니다.") | ||
| @Schema(description = "GitHub 주소", example = "https://github.com/username", required = true) | ||
| private String githubLink; // 깃허브 주소 | ||
|
|
||
| @NotBlank(message = "포트폴리오 주소는 필수 입력 값입니다.") | ||
| @URL(protocol = "https", message = "포트폴리오 URL이 올바르지 않습니다.") | ||
| @Schema(description = "포트폴리오 주소", example = "https://portfolio.com/username", required = true) | ||
| private String portfolioLink; // 포트폴리오 주소 | ||
| } | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,4 +31,10 @@ public class SomParticipantResponseDto { | |
|
|
||
| @Schema(description = "이메일 주소", example = "[email protected]", required = true) | ||
| private String email; // 이메일 | ||
| } | ||
|
|
||
| @Schema(description = "깃허브 주소", example = "https://github.com/username", required = true) | ||
| private String githubLink; // 깃허브 주소 | ||
|
|
||
| @Schema(description = "포트폴리오 주소", example = "https://portfolio.com/username", required = true) | ||
| private String portfolioLink; // 포트폴리오 주소 | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. SomParticipantService.toResponseDto() 로직을 여기 하단에 추가해주심 됩니다. 엔티티 캡슐화나 책임 분리? 라는 내용으로 찾아보심 될 것 같아요 There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 리뷰 감사합니다! 수정 완료했습니다! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -39,12 +39,20 @@ public class SomParticipant extends BaseEntity { | |
| @Column(nullable = false) | ||
| private String email; // 이메일 | ||
|
|
||
| @Column(nullable = false) | ||
|
||
| private String githubLink; // 깃허브 링크 | ||
|
|
||
| @Column(nullable = false) | ||
| private String portfolioLink; // 포트폴리오 링크 | ||
|
|
||
| public void update(SomParticipantRequestDto requestDto) { | ||
| this.participantName = requestDto.getParticipantName(); | ||
| this.studentId = requestDto.getStudentId(); | ||
| this.department = requestDto.getDepartment(); | ||
| this.grade = requestDto.getGrade(); | ||
| this.contact = requestDto.getContact(); | ||
| this.email = requestDto.getEmail(); | ||
| this.githubLink = requestDto.getGithubLink(); | ||
| this.portfolioLink = requestDto.getPortfolioLink(); | ||
| } | ||
| } | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 이 부분을 서비스단에서 처리하는게 아니라 엔티티 단계에서 처리하도록 수정해주세요! There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 넵 리뷰 감사합니다! 수정 완료했습니다! |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,182 @@ | ||
| package dmu.dasom.api.domain.somkathon; | ||
|
|
||
| import dmu.dasom.api.domain.common.exception.CustomException; | ||
| import dmu.dasom.api.domain.common.exception.ErrorCode; | ||
| import dmu.dasom.api.domain.somkathon.dto.SomParticipantRequestDto; | ||
| import dmu.dasom.api.domain.somkathon.dto.SomParticipantResponseDto; | ||
| import dmu.dasom.api.domain.somkathon.entity.SomParticipant; | ||
| import dmu.dasom.api.domain.somkathon.repository.SomParticipantRepository; | ||
| import dmu.dasom.api.domain.somkathon.service.SomParticipantService; | ||
| import org.junit.jupiter.api.DisplayName; | ||
| import org.junit.jupiter.api.Test; | ||
| import org.junit.jupiter.api.extension.ExtendWith; | ||
| import org.mockito.InjectMocks; | ||
| import org.mockito.Mock; | ||
| import org.mockito.junit.jupiter.MockitoExtension; | ||
|
|
||
| import java.util.List; | ||
| import java.util.Optional; | ||
|
|
||
| import static org.junit.jupiter.api.Assertions.*; | ||
| import static org.mockito.Mockito.*; | ||
|
|
||
| @ExtendWith(MockitoExtension.class) | ||
| class SomParticipantServiceTest { | ||
|
|
||
| @Mock | ||
| private SomParticipantRepository repository; | ||
|
|
||
| @InjectMocks | ||
| private SomParticipantService service; | ||
|
|
||
| // ======================= | ||
| // Create Tests | ||
| // ======================= | ||
| @Test | ||
| @DisplayName("참가자 생성 - 성공") | ||
| void createParticipant_success() { | ||
| SomParticipantRequestDto request = new SomParticipantRequestDto(); | ||
| request.setParticipantName("홍길동"); | ||
| request.setStudentId("20250001"); | ||
| request.setDepartment("컴퓨터공학과"); | ||
| request.setGrade("3"); | ||
| request.setContact("010-1234-5678"); | ||
| request.setEmail("[email protected]"); | ||
| request.setGithubLink("https://github.com/username"); | ||
| request.setPortfolioLink("https://drive.google.com/file"); | ||
|
|
||
| when(repository.findByStudentId("20250001")).thenReturn(Optional.empty()); | ||
| when(repository.save(any(SomParticipant.class))).thenAnswer(invocation -> invocation.getArgument(0)); | ||
|
|
||
| SomParticipantResponseDto response = service.createParticipant(request); | ||
|
|
||
| assertNotNull(response); | ||
| assertEquals("홍길동", response.getParticipantName()); | ||
| assertEquals("20250001", response.getStudentId()); | ||
| assertEquals("컴퓨터공학과", response.getDepartment()); | ||
| assertEquals("3", response.getGrade()); | ||
| assertEquals("010-1234-5678", response.getContact()); | ||
| assertEquals("[email protected]", response.getEmail()); | ||
| assertEquals("https://github.com/username", response.getGithubLink()); | ||
| assertEquals("https://drive.google.com/file", response.getPortfolioLink()); | ||
|
|
||
| verify(repository, times(1)).findByStudentId("20250001"); | ||
| verify(repository, times(1)).save(any(SomParticipant.class)); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("참가자 생성 - 실패 (학생ID 중복)") | ||
| void createParticipant_fail_duplicateStudentId() { | ||
| SomParticipantRequestDto request = new SomParticipantRequestDto(); | ||
| request.setStudentId("20250001"); | ||
|
|
||
| when(repository.findByStudentId("20250001")).thenReturn(Optional.of(mock(SomParticipant.class))); | ||
|
|
||
| CustomException exception = assertThrows(CustomException.class, () -> service.createParticipant(request)); | ||
| assertEquals(ErrorCode.DUPLICATED_STUDENT_NO, exception.getErrorCode()); | ||
|
|
||
| verify(repository, times(1)).findByStudentId("20250001"); | ||
| verify(repository, never()).save(any()); | ||
| } | ||
|
|
||
| // ======================= | ||
| // Read Tests | ||
| // ======================= | ||
| @Test | ||
| @DisplayName("모든 참가자 조회") | ||
| void getAllParticipants_success() { | ||
| SomParticipant p1 = SomParticipant.builder() | ||
| .participantName("홍길동") | ||
| .studentId("20250001") | ||
| .department("컴퓨터공학과") | ||
| .grade("3") | ||
| .contact("010-1234-5678") | ||
| .email("[email protected]") | ||
| .githubLink("https://github.com/hong") | ||
| .portfolioLink("https://drive.google.com/file") | ||
| .build(); | ||
| SomParticipant p2 = SomParticipant.builder() | ||
| .participantName("김철수") | ||
| .studentId("20250002") | ||
| .department("소프트웨어공학과") | ||
| .grade("2") | ||
| .contact("010-9876-5432") | ||
| .email("[email protected]") | ||
| .githubLink("https://github.com/kim") | ||
| .portfolioLink("https://notion.site") | ||
| .build(); | ||
|
|
||
| when(repository.findAll()).thenReturn(List.of(p1, p2)); | ||
|
|
||
| List<SomParticipantResponseDto> list = service.getAllParticipants(); | ||
|
|
||
| assertEquals(2, list.size()); | ||
|
|
||
| assertEquals("홍길동", list.get(0).getParticipantName()); | ||
| assertEquals("김철수", list.get(1).getParticipantName()); | ||
|
|
||
| assertEquals("https://github.com/hong", list.get(0).getGithubLink()); | ||
| assertEquals("https://notion.site", list.get(1).getPortfolioLink()); | ||
|
|
||
| verify(repository, times(1)).findAll(); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("특정 참가자 조회 - 성공") | ||
| void getParticipant_success() { | ||
| SomParticipant participant = SomParticipant.builder() | ||
| .participantName("홍길동") | ||
| .studentId("20250001") | ||
| .department("컴퓨터공학과") | ||
| .grade("3") | ||
| .contact("010-1234-5678") | ||
| .email("[email protected]") | ||
| .githubLink("https://github.com/username") | ||
| .portfolioLink("https://drive.google.com/file") | ||
| .build(); | ||
|
|
||
| when(repository.findById(1L)).thenReturn(Optional.of(participant)); | ||
|
|
||
| SomParticipantResponseDto response = service.getParticipant(1L); | ||
|
|
||
| assertEquals("홍길동", response.getParticipantName()); | ||
| assertEquals("20250001", response.getStudentId()); | ||
|
|
||
| verify(repository, times(1)).findById(1L); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("특정 참가자 조회 - 실패 (없음)") | ||
| void getParticipant_fail_notFound() { | ||
| when(repository.findById(1L)).thenReturn(Optional.empty()); | ||
|
|
||
| CustomException exception = assertThrows(CustomException.class, () -> service.getParticipant(1L)); | ||
| assertEquals(ErrorCode.NOT_FOUND_PARTICIPANT, exception.getErrorCode()); | ||
|
|
||
| verify(repository, times(1)).findById(1L); | ||
| } | ||
|
|
||
| // ======================= | ||
| // Delete Tests | ||
| // ======================= | ||
| @Test | ||
| @DisplayName("참가자 삭제 - 성공") | ||
| void deleteParticipant_success() { | ||
| SomParticipant participant = SomParticipant.builder().build(); | ||
| when(repository.findById(1L)).thenReturn(Optional.of(participant)); | ||
|
|
||
| assertDoesNotThrow(() -> service.deleteParticipant(1L)); | ||
| verify(repository, times(1)).deleteById(1L); | ||
| } | ||
|
|
||
| @Test | ||
| @DisplayName("참가자 삭제 - 실패 (없음)") | ||
| void deleteParticipant_fail_notFound() { | ||
| when(repository.findById(1L)).thenReturn(Optional.empty()); | ||
|
|
||
| CustomException exception = assertThrows(CustomException.class, () -> service.deleteParticipant(1L)); | ||
| assertEquals(ErrorCode.NOT_FOUND_PARTICIPANT, exception.getErrorCode()); | ||
|
|
||
| verify(repository, never()).deleteById(any()); | ||
| } | ||
| } |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
requestDto는 객체 생성 후 변하면 안되어서 @Setter 제거 후 내부 필드 전부 final로 수정해주시면 감사하겠습니다. 그리고 추가로 @AllArgsConstructor 추가해서 빌더 패턴 유지해주시면 될 것 같습니다. 이 내용은 불변성 관련 내용이라서 DTO 불변성 이나 불변 객체 DTO 이런식으로 검색하시면 자료가 많을겁니다. (umc 워크북에서도 하셨던 내용이라 보시면 바로 이해하실거에요)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
넵 리뷰 감사합니다! 수정 완료했습니다!