본문 바로가기
Project/깃터디 (gitudy)

[깃터디/Convention] 컨벤션 등록 api 구현

by J-rain 2024. 5. 11.

💡 .java를 클릭시 관련 커밋으로 이동💡

 

 회고 

    @ApiResponse(responseCode = "200", description = "컨벤션 등록 성공")
    @PostMapping("/")
    public JsonResult<?> registerStudyConvention(@AuthenticationPrincipal User user,
                                                 @RequestParam(name = "studyInfoId") Long studyInfoId,

StudyConventionController 에서 studyInfoId 를 @RequestParam 어노테이션 즉, 쿼리 파라미터로 처리를 했었지만 쿼리 파라미터는 주로 filter값이나 pagination에 필요한 정보(cursorIdx, limit등) 비교적 간단한 정보를 전달하는 데 적합하다는 것을 깨달았다!!

 

⏬ 변경

StudyConventionController.java

@Slf4j
@RestController
@RequiredArgsConstructor
@RequestMapping("/convention")
public class StudyConventionController {

    private final StudyConventionService studyConventionService;
    private final StudyMemberService studyMemberService;

    @ApiResponse(responseCode = "200", description = "컨벤션 등록 성공")
    @PostMapping("/")
    public JsonResult<?> registerStudyConvention(@AuthenticationPrincipal User user,
                                                 @Valid @RequestBody StudyConventionRequest studyConventionRequest) {

        studyMemberService.isValidateStudyLeader(user, studyConventionRequest.getStudyInfoId());

        studyConventionService.registerStudyConvention(studyConventionRequest);

        return JsonResult.successOf("StudyConvention register Success");
    }
}

@RequestBody 를 사용하여 DTO에 studyInfoId를 넣어주었다 ⇒ 사용자가 직접 입력하는 방식이 아닌 프론트에서 등록한 값에 studyInfoId를 추가하여 넣어줄 예정

나중에 다시 @PathValiable 로 변경하여 studyInfoId를 받아주었다. ㅎㅎ,, 그이유는

Todo api 구현할때 그렇게 사용하기도 했고 (통일성) + 컨벤션 삭제 api 구현하면서 url에 혼동이 올수도 있겠다 싶어서 변경하게되었..

 

StudyConventionRequest.java

@Getter
@AllArgsConstructor
@NoArgsConstructor
@Builder
public class StudyConventionRequest {

    private Long studyInfoId; // 스터디 Id

    @NotBlank(message = "컨벤션 이름은 공백일 수 없습니다.")
    @Size(max = 20, message = "이름 20자 이내")
    private String name;   // 컨벤션 이름

    @Size(max = 50, message = "설명 50자 이내")
    private String description; // 컨벤션 설명

    @NotBlank(message = "컨벤션 내용은 공백일 수 없습니다.")
    @Size(max = 40, message = "내용 40자 이내")
    private String content;  // 컨벤션 내용(정규식)

    @Builder.Default
    private boolean active = true; // 컨벤션 적용 여부
}

Dto 추가

 

StudyConventionService.java

@Slf4j
@Service
@Transactional(readOnly = true)
@RequiredArgsConstructor
public class StudyConventionService {

    private final StudyConventionRepository studyConventionRepository;

    // 컨벤션 등록
    @Transactional
    public void registerStudyConvention(StudyConventionRequest request) {

        // 컨벤션 저장
        studyConventionRepository.save(StudyConvention.builder()
                .studyInfoId(request.getStudyInfoId())
                .name(request.getName())
                .description(request.getDescription())
                .content(request.getContent())
                .isActive(request.isActive())
                .build());
    }
}

Convention 등록 Service 구현

 


테스트

 

StudyConventionFixture.java

public class StudyConventionFixture {

    // 테스트용 컨벤션 등록
    public static StudyConventionRequest generateStudyConventionRequest(Long studyInfoId) {
        return StudyConventionRequest.builder()
                .studyInfoId(studyInfoId)
                .name("컨벤션")
                .description("설명")
                .content("정규식")
                .active(true)
                .build();
    }

}

컨벤션 등록을 위한 Convention Fixture 작성

 

 

StudyConventionControllerTest.java

    @Test
    public void Convetion_등록_테스트() throws Exception {
        //given

        User savedUser = userRepository.save(generateAuthUser());
        Map<String, String> map = TokenUtil.createTokenMap(savedUser);
        String accessToken = jwtService.generateAccessToken(map, savedUser);
        String refreshToken = jwtService.generateRefreshToken(map, savedUser);

        StudyInfo studyInfo = StudyInfoFixture.createDefaultPublicStudyInfo(savedUser.getId());
        studyInfoRepository.save(studyInfo);

        StudyConventionRequest request = StudyConventionFixture.generateStudyConventionRequest(studyInfo.getId());

        doNothing().when(studyMemberService).isValidateStudyLeader(any(User.class), any(Long.class));
        doNothing().when(studyConventionService).registerStudyConvention(any(StudyConventionRequest.class));

        //when , then
        mockMvc.perform(post("/convention/")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header(AUTHORIZATION, createAuthorizationHeader(accessToken, refreshToken))
                        .content(objectMapper.writeValueAsString(request)))
                .andExpect(status().isOk())
                .andExpect(jsonPath("$.res_code").value(200))
                .andExpect(jsonPath("$.res_msg").value("OK"))
                .andExpect(jsonPath("$.res_obj").value("StudyConvention register Success"))
                .andDo(print());

    }

    @Test
    public void Convention_등록_유효성_검증_실패_테스트() throws Exception {
        //given
        String inValidName = "   ";
        String expectedError = "name: 컨벤션 이름은 공백일 수 없습니다.";

        User savedUser = userRepository.save(generateAuthUser());
        Map<String, String> map = TokenUtil.createTokenMap(savedUser);
        String accessToken = jwtService.generateAccessToken(map, savedUser);
        String refreshToken = jwtService.generateRefreshToken(map, savedUser);

        //when , then
        mockMvc.perform(post("/convention/")
                        .contentType(MediaType.APPLICATION_JSON)
                        .header(AUTHORIZATION, createAuthorizationHeader(accessToken, refreshToken))
                        .content(objectMapper.writeValueAsString(StudyConventionRequest.builder()
                                .name(inValidName)
                                .content("정규식")
                                .build())))

                .andExpect(status().isOk())
                .andExpect(jsonPath("$.res_code").value(400))
                .andExpect(jsonPath("$.res_msg").value(expectedError))
                .andDo(print());
    }

컨트롤러 동작 검증 ( HTTP 요청을 올바르게 처리하고 적절한 응답을 반환하는지 확인)

Convention 등록을 성공했을때 → Convetion_등록_테스트()

Convention 등록을 실패했을때 (유효성 검증) → Convention_등록_유효성_검증_실패_테스트()

으로 나누어 테스트했다.

유효성 검증으로는 @NotBlank 공백일 경우 → 예외(실패)를 터트리는지 확인

 

 

StudyConventionServiceTest.java

    @Test
    @DisplayName("컨벤션 등록 테스트")
    public void registerConvention() {
        //given
        User savedUser = userRepository.save(generateAuthUser());

        StudyInfo studyInfo = StudyInfoFixture.createDefaultPublicStudyInfo(savedUser.getId());
        studyInfoRepository.save(studyInfo);

        StudyMember leader = StudyMemberFixture.createStudyMemberLeader(savedUser.getId(), studyInfo.getId());
        studyMemberRepository.save(leader);

        StudyConventionRequest request = StudyConventionFixture.generateStudyConventionRequest(studyInfo.getId());

        //when
        studyMemberService.isValidateStudyLeader(savedUser, studyInfo.getId());
        studyConventionService.registerStudyConvention(request);
        StudyConvention findConvention = studyConventionRepository.findByStudyInfoId(studyInfo.getId());

        //then
        assertEquals("컨벤션", findConvention.getName());
        assertEquals("설명", findConvention.getDescription());
        assertEquals("정규식", findConvention.getContent());

    }

ConventionService 등록 테스트

댓글