프론트엔드 팀으로부터 페이지 조회의 응답 DTO의 필드명을 수정해 달라는 요청이 있었다. 기존에는
{
"hasNext": "true",
"keyboards": [
...
]
}
의 형태였다면, keyboards
로 보내준 리스트를 items
로 보내달라는 요청이었다.
거기에 추가로 백엔드끼리 논의한 결과, 리뷰 도메인에 추가한 createdAt
필드를 DTO에도 담아 주어야 한다는 의견이 나왔다. 처음에는 createdAt
이 정렬에만 쓰일 거라 생각했지만, 각각의 리뷰가 생성된 시점도 클라이언트로 보내주는 것이 자연스럽다는 생각에서였다.
처음 계획으로는 XXXControllerTest
와 같은 컨트롤러에 대한 슬라이스 테스트를 만들지 않을 생각이었다. 어차피 REST Docs
를 만드는 과정에서도 테스트 코드가 필요하기 때문에, 인수 테스트 + REST Docs만으로 충분히 컨트롤러단에 대한 테스트가 가능하다고 생각했기 때문이다. 하지만 프론트엔드에서 한 번 걸러주기 때문에 실제 유저 시나리오에서는 발생할 가능성이 없는 예외에 대해 백엔드 단에서도 처리한 결과를 테스트해야 할 필요가 있었는데, 이런 케이스는 인수 테스트나 documentation에서 테스트를 진행하지 않기 때문에 결과적으로 각각의 api 주소에 대한 응답 성공 / 실패의 테스트를 해 줄 필요가 있다는 생각이 들었다. 그래서 @WebMvcTest
+ mocking을 사용한 컨트롤러의 슬라이스 테스트를 진행하기로 결정했다. 굳이 @SpringBootTest
로 E2E 테스트를 진행할 필요는 없다고 생각했는데, 컨트롤러 슬라이스 테스트는 api 주소가 제대로 매핑되어있는지와 서비스 단에서 로직의 결과(객체나 예외)를 반환하면 정상적으로 HTTP Response로 바꿔주는지만 검증하면 되기 때문에 굳이 모든 환경을 실제와 똑같이 구성할 필요가 없다고 생각했다.
@Test
void 리뷰_생성_실패_리뷰_내용이_존재하지_않음() throws Exception {
// given
given(reviewService.save(anyLong(), any(ReviewRequest.class)))
.willThrow(new BlankContentException());
ReviewRequest reviewRequest = new ReviewRequest("", 5);
// when
mockMvc.perform(
post("/api/v1/keyboards/" + PRODUCT_ID + "/reviews")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(reviewRequest))
).andExpect(status().isBadRequest())
.andDo(print());
// then
verify(reviewService).save(eq(PRODUCT_ID), any(ReviewRequest.class));
}
검증한 것은 두 가지로, 정상적인 상태 코드가 나왔는지(성공했으면 성공에 맞는 상태 코드, 예외가 반환되어 ControllerAdvice가 예외를 잡았다면 그 예외에 맞는 상태 코드)와, mocking한 서비스 메서드가 정상적으로 호출 되었는지의 여부를 검증했다. 이를 통해 api URL이 제대로 매핑되었는지, 예외 상황에서도 의도한 HTTP response가 정상적으로 반환되는지에 대해 테스트를 수행할 수 있었다.
큰 이슈는 아니었고, 프론트엔드와의 연결 시 애플리케이션을 돌릴 로컬 환경을 세팅해야 하는 이슈가 있었다. 테스트 환경처럼 휘발성 인메모리 DB를 사용하게 되면 데모 실행 시 마다 필요한 데이터를 넣는 작업을 반복해주어야 하기 때문에 데모를 위한 환경으로 적절하지 못했다.
그래서 main 쪽의 application.yml
과 test 쪽의 application.yml
을 각각 작성하여 로컬 빌드 환경과 테스트 환경을 분리해주었다. 사실 아직 큰 차이는 없고, datasource url과 ddl-auto
옵션만 달라졌다.
main/resources/application.yml
spring:
datasource:
url: jdbc:h2:tcp://localhost/~/f12;MODE=MySQL
username: sa
password:
jpa:
hibernate:
ddl-auto: none
show-sql: true
properties:
hibernate:
format_sql: true
h2:
console:
enabled: true
path: /h2-console
server:
port: 8080
test/resources/application.yml
spring:
jpa:
hibernate:
ddl-auto: create
show-sql: true
properties:
hibernate:
format_sql: true
server:
port: 8080
이 설정을 통해 테스트 환경에서는 스프링부트 내장 인메모리 h2 데이터베이스를 사용하고, 로컬 빌드 환경에서는 tcp 통신을 이용한 로컬 h2 데이터베이스(휘발성이 없다)를 사용하도록 설정해주었다.
내일은 오늘 마무리하지 못한 프론트엔드와의 로컬 빌드 연결을 마무리하고, 데모에 필요한 데이터를 충분히 삽입해 놓는 등 데모 데이를 준비하는 작업을 진행할 예정이다.
비즈니스 코드 적으로는 제품에 대한 리뷰를 작성 또는 조회할 때 제품이 존재하는지 확인하는 로직을 추가하고, 난잡한 테스트 코드를 리팩토링 하는 것을 목표로 한다.
잘 보고 갑니다 :)