TIL

2024-09-09 ~ 2024-09-13 WIL

Coding-Su 2024. 10. 11. 15:33
728x90

1. Spring 심화 주차 개인 과제 ( Test 코드 학습 )

이번주에 AOP와 테스트 코드에 대해 배웠습니다.

 

AOP

AOP는 관점 지향 프로그래밍으로, 관점을 기준으로 다양한 기능을 분리하여 보는 프로그래밍입니다.

 

AOP는 런타임 시점에 적용하는 방식으로 공통기능을 작성할 때 매우 유용하게 사용됩니다. 따라서 저는 프로젝트에서 어드민 사용자만 접근할 수 있는 특정 API에는 접근할 때마다 접근 로그를 기족하기 위해 AOP를 사용하였습니다. 

 

이때 저는 AOP를 어노테이션 방식으로 사용하였습니다.

 

어노테이션 선언

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface InfoAnnotation {
}

 

어노테이션 구현

@Slf4j
@Aspect
@Component
public class InfoAop {

    @Pointcut("@annotation(org.example.expert.anno.InfoAnnotation)")
    private void infoAnnotation() {}

    /**
     * 어드바이스: 어노테이션 범위 기반
     */
    @Around("infoAnnotation()")
    public Object info(ProceedingJoinPoint joinPoint) throws Throwable {
        //측정 시작
        String currentTime = LocalDateTime.now().toString();

        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.currentRequestAttributes()).getRequest();
        Long userId = (Long) request.getAttribute("userId");

        try {
            Object result = joinPoint.proceed();
            return result;
        } finally {
            // 측정 완료
            log.info("::: User Id: {}", userId);
            log.info("::: API 실행시간: {}ms", currentTime);
            log.info("::: API URL: {}", request.getRequestURI());
        }
    }
}

 

어노테이션 적용

@RestController
@RequiredArgsConstructor
public class UserAdminController {

    private final UserAdminService userAdminService;

    @InfoAnnotation
    @PatchMapping("/admin/users/{userId}")
    public void changeUserRole(@PathVariable(name = "userId") long userId, @RequestBody UserRoleChangeRequest userRoleChangeRequest) {
        userAdminService.changeUserRole(userId, userRoleChangeRequest);
    }
}

 

 

 

테스트 코드 작성

Service 테스트 코드 작성

서비스 테스트 코드 작성할 때 @ExtendWith(MockitoExtension.class)를 사용하여 test 코드를 작성하였습니다.

 

작성한 테스트코드 중 하나 예시

@ExtendWith(MockitoExtension.class)
class CommentAdminServiceTest {

    @Mock
    CommentRepository commentRepository;

    @InjectMocks
    CommentAdminService commentAdminService;

    @Nested
    class deleteComment {
        @Test
        void comment_삭제() {
            // given
            long commentId = 1L;

            doNothing().when(commentRepository).deleteById(anyLong());

            // when
            commentAdminService.deleteComment(commentId);

            // then
            verify(commentRepository, times(1)).deleteById(anyLong());
        }
    }
}

 

@Mock을 통해 가짜를 넣어주고, @InjectMock을 통해 테스트할 service를 주입하였습니다.

 

@Nested는 여러개의 test코드를 묶어주기 위해 사용하는 코드입니다.

 

테스트 코드는  given, when, then 방식으로 given으로 원하는 값을 주고, when을 통해 상황을 적고, then을 통해 값을 예상하였습니다. 위 코드 부분은 comment 삭제 부분에 관한 테스트 코드입니다.

 

verity를 사용한 이유는 삭제 메서드의 경우 반환이 없는 void 여서 이 함수가 실행이 되었는지 확인하기 위해 사용하였습니다.

 

 

 

Controller 테스트 코드 작성

컨트롤러 테스트 코드는 @WebMvcTest를 사용하여 test 코드를 작성하였습니다.

 

작성한 테스트코드 중 예시

@WebMvcTest(CommentAdminController.class)
class CommentAdminControllerTest {
    
    @Autowired
    private MockMvc mvc;
    
    @MockBean
    private CommentAdminService commentAdminService;


    @Test
    void 삭제_성공() throws Exception {
        // given
        long commentId = 1L;

        doNothing().when(commentAdminService).deleteComment(commentId);
        
        // when
        mvc.perform(delete("/admin/comments/{commentId}", commentId));

        //then
        verify(commentAdminService, times(1)).deleteComment(anyLong());
    }
}

 

@WebMvcTest를 사용해서 어떤 컨트롤러를 테스트 할지 적어주고, @Autowired를 사용하여 MockMvc를 주입하였습니다. 그 다음 @MockBean을 사용하여 서비스를 수동 빈 주입을 하지 않고 동적으로 Mock 개체를 빈으로 등록하였습니다.

 

mvc.perform()을 이용하여 HTTP 요청을 실행하여 테스트를 진행하였습니다.

 

마지막 then에서 verify를 사용하여 실행되었는지 확인하였습니다.

 

 

 

 

 

 

여러 테스트 코드들을 작성하여 최대한 테스트 커버리지의 작성률을 높이도록 하였습니다. github에는 auth를 이용한 부분에서의 test 코드, resultActions를 이용하여 확인하기, assertEquals, assertNotNull 등을 활용하였습니다.

 

Spring 심화 주차 개인 과제 깃허브 주소

 

GitHub - SuHyun-git/spring-advanced

Contribute to SuHyun-git/spring-advanced development by creating an account on GitHub.

github.com

 

728x90

'TIL' 카테고리의 다른 글

2024-09-19 ~ 2024-09-25 WIL  (4) 2024.10.12
20240910_TIL  (0) 2024.09.11
20240909_TIL  (0) 2024.09.11
20240906_TIL  (1) 2024.09.08
20240905_TIL  (0) 2024.09.05