성장 화면 API의 단독 MockMvc 테스트를 작성하고 실행하니 정상 요청과 400을 기대한 요청이 모두 500으로 실패했습니다. 로그를 따라가 보니 컨트롤러의 @AuthenticationPrincipal jwt: Jwt에 값이 들어오지 않았습니다. Kotlin은 non-null 매개변수에 null이 넘어오는 순간 예외를 던졌고, 요청은 정작 검사하려던 코드까지 가지 못했습니다.

인자 해석기와 예외 처리기 등록

standaloneSetup은 제가 넘긴 컨트롤러를 중심으로 작은 MVC 환경을 만듭니다. 실제 앱에서 쿠키를 읽고 JWT를 검증하는 보안 필터까지 자동으로 붙지는 않습니다. 요청에 인증 후처리기만 붙인 첫 테스트에서는 컨트롤러가 읽을 인증 정보가 비어 있었습니다.

단독 테스트에는 AuthenticationPrincipalArgumentResolver를 직접 등록하고, 검증을 통과한 사용자를 가정한 인증 객체를 테스트마다 컨텍스트에 넣었습니다. 끝나면 컨텍스트를 비워 다른 테스트로 상태가 새지 않게 했습니다. 공통 예외 처리기도 직접 등록했습니다. Spring MVC가 입력 오류를 400으로 처리하더라도 공통 처리기가 빠지면 앱이 기대하는 result.errorCode는 본문에 없을 수 있기 때문입니다.

이 구성에서 정상 요청은 저장소 대역으로 사용자의 ID를 넘겼고, 잘못된 쿼리 형식은 공통 오류 코드가 있는 400으로 돌아왔습니다. 분석 재시도 API의 단독 검사에서도 경로 인자와 요청 헤더의 MVC 검증을 확인했습니다. 경로 인자의 양수 제약을 제거하면 해당 테스트가 실패했습니다.

얼쑤의 발급 규칙에서는 토큰의 sub에 회원 ID를 담습니다. 컨트롤러는 검증된 Jwt에서 sub를 꺼내 정수 회원 ID로 변환하고, 성장 기록을 읽는 서비스에 넘깁니다. 단독 검사에서는 가정한 인증 정보가 같은 ID로 조회에 쓰였는지 확인했습니다.

실제 HTTP에서 서명 쿠키 확인

실제 HTTP 통합 테스트는 앱을 임의 포트로 띄우고 테스트 키로 서명한 JWT를 쿠키에 실어 요청했습니다. 유효한 쿠키로 성장 기록을 조회했고 쿠키를 빼면 401이 돌아왔습니다. 이쪽은 보안 필터, 컨트롤러, MySQL이 이어지는 경로를 확인했습니다. 단독 검사는 인증 이후의 처리 분기를 좁게 검사하고, 통합 검사는 그 인증 상태가 실제 요청에서 어떻게 만들어지는지 확인하도록 나눴습니다.