TDD 연습 프로젝트 4 - 멤버십 API 구현 (Membership Controller)

zunzero·2022년 9월 6일
1

스프링, JPA

목록 보기
12/23

멤버십 등록 API

요구사항

  • 나의 멤버십 등록 API
    - 기능: 나의 멤버십을 등록합니다.
    • 요청: 사용자 식별값, 멤버십 이름, 포인트
    • 응답: 멤버십 ID, 멤버십 이름

Controller 계층 개발

역시 마찬가지로 테스트 코드를 먼저 작성해야 한다.
컨트롤러는 함수 호출이 아닌 API 호출을 통해 요청을 받아 응답을 처리해야하며, 메세지 컨버팅 등과 같은 작업이 필요하다.
따라서 Mock MVC 라는 클래스를 이용한다.

첫번째 테스트는 Mock MVC 초기화 테스트이다.

테스트의 대상이 될 클래스에 @InjectMocks 어노테이션을 달아준다.
Gson은 스프링부트에서 객체를 Json으로 편리하게 바꿔준다.

컴파일 에러 수정을 위해 MembershipController 클래스를 만들고, 테스트 코드를 다음과 같이 바꿔준다.

mockMvc는 다른 테스트에서도 사용이 될 것으로 보이므로, 각각의 테스트가 실행되기 전에 초기화를 도와주는 @BeforeEach를 사용해서 리팩토링 한다.

이제 본격적인 API 개발을 진행해보자.!

우선 사용자 식별값이 헤더에 없어서 실패하는 케이스부터 작성해보도록 하자.

해당 에러를 해결하기 위해 우선 request DTO 클래스를 만들고, url에 해당하는 API를 개발하도록 하겠다.

다음과 같이 코드를 수정한 후, 헤더에 식별값이 없어서 Bad Request 응답 처리를 하는 테스트가 성공하였다.

이번엔 사용자가 보낸 데이터 중 포인트가 음수이거나 null인 경우, 혹은 멤버십 타입이 null인 경우 실패하는 테스트 코드를 작성해보겠다.

소스 코드를 고치고 테스트를 돌리면 실패한다.
왜냐하면 해당 값들에 대한 유효성 검사를 진행하지 않았기 때문이다.
Javax의 Validation 기능인 @Valid 어노테이션을 이용해서 유효성 검사를 진행할 수 있다.

implementation 'org.springframework.boot:spring-boot-starter-validation'

build.gradle에 의존성을 추가해준다.

다음과 같이 코드를 수정하고 테스트를 진행하면 테스트가 성공한다.

다음은 MembershipService에서 throw한 Exception을 처리하기 위한 @RestControllerAdvice를 구현하기 위해 테스트 코드를 작성하고자 한다.

위와 같이 테스트 코드를 짜서 실행시켜 보면 실패하게 된다.
당연하다.
Controller에서 Service를 실행하지 않고, 유효성 검사만 한 후에 문제가 없으면 Created 응답을 하기 때문이다.
따라서 Controller에서 Service를 실행해서 어떤 결과를 가져오는 지에 대한 로직을 구현해야 한다.

위와 같이 코드를 수정하고 테스트를 해보아도 실패하게 되는데, 이는 Exception 예외를 잡아서 HttpStatus와 에러메세지로 반환하도록 도와주는 @RestControllerAdvice 부분이 개발되지 않았기 때문이다.

따로 Advice의 영역(?)을 설정해주지 않았기 때문에 모든 컨트롤러에서 Advice의 ExceptionHandler가 처리해주는 Exception이 발생했을 때, 전역적으로 이를 잡아서 처리한다.
모든 Exception의 조상인 Exception.class까지 처리하기 때문에 모든 Exception을 처리할 수 있다.
오버라이딩 된 handleMethodArgumentNotValid는 @Valid에서 예외가 발생할 경우에 처리하게 되는 메서드다.
@WebMvcTest를 이용하면 GlobalExceptionHandler가 자동으로 추가되었겠지만, 우리는 현재 직접 MockMvc를 생성하고 있으므로, MockMvc 생성 과정에 GlobalExceptionHandler를 추가해주어야 한다.

마지막으로 이제는 멤버십 등록이 성공하는 테스트 케이스를 작성하여, API 구현을 완성하면 된다.

작성된 테스트 코드는 NullPointerException을 던지며 실패한다.
Controller에서 응답 body에 아무것도 담지 않기 때문에, 테스트 코드의 response가 null값이 되는 것이다.
따라서 우리는 Controller 코드를, 응답 body에 요구사항을 이행하는 데이터를 담도록 수정해야 한다.

테스트가 깔끔히 성공했다.

MockMVC, Mockito, JUnit 등 아직 모르는 부분이 한참 많은 것 같다.
이 부분에 대한 공부를 추후에 따로 하도록 하겠다.

profile
나만 읽을 수 있는 블로그

0개의 댓글