MockMvc를 사용해서 Controller를 Test할 때 BDD를 적용해서 가독성을 향상시키는 방법에 대해 알아보자.
기존의 코드를 살펴보자.
기존
기존의 코드는 다음과 같았다.
@Test
@DisplayName("유저를 생성할 수 있다.")
void signup() throws Exception {
SignUpRequest signUpRequest = SignUpRequest.builder()
.loginId("test123")
.password("password12@")
.name("TestName")
.birthday(LocalDate.of(1994, 2, 10))
.phone("01012345678")
.allowToMarketingNotification(true)
.build();
mockMvc.perform(post("/accounts")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(signUpRequest)))
.andExpect(status().isCreated())
.andExpect(jsonPath("login_id").value(signUpRequest.getLoginId()))
.andDo(document("계정 등록",
getDocumentRequest(),
getDocumentResponse(),
requestFields(
fieldWithPath("login_id").type(JsonFieldType.STRING).description("계정 로그인 ID"),
fieldWithPath("password").type(JsonFieldType.STRING).description("계정 비밀번호"),
fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("phone").type(JsonFieldType.STRING).description("전화번호"),
fieldWithPath("birthday").type(JsonFieldType.STRING).description("생년월일").optional(),
fieldWithPath("allow_to_marketing_notification").type(JsonFieldType.BOOLEAN).description("마케팅 정보 수신 동의 여부")
),
responseFields(
fieldWithPath("id").type(JsonFieldType.NUMBER).description("계정 일련번호"),
fieldWithPath("login_id").type(JsonFieldType.STRING).description("계정 로그인 ID")
)));
}
문제는 해당 코드에는 경계가 없어서 가독성이 떨어졌다.
테스트를 위해 데이터를 초기화하는 영역은 어느 부분인지, 테스트를 실행하는 부분은 어느 부분인지, 테스트를 검증하는 부분은 어느 부분인지 도무지 이해를 할 수가 없다. 즉, 검증의 목적만 있을 뿐 테스트를 이해하기 힘들고 가독성이 떨어진다.
하지만 Controller Test에도 BDD를 적용할 수 있다.
다음의 예제를 보자.
BDD를 적용한 예제
@Test
@DisplayName("유저를 생성할 수 있다.")
void signup() throws Exception {
// given
SignUpRequest signUpRequest = SignUpRequest.builder()
.loginId("test123")
.password("password12@")
.name("TestName")
.birthday(LocalDate.of(1994, 2, 10))
.phone("01012345678")
.allowToMarketingNotification(true)
.build();
// when
ResultActions result = mockMvc.perform(post("/accounts")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(signUpRequest)));
// then
result.andExpect(status().isCreated())
.andExpect(jsonPath("login_id").value(signUpRequest.getLoginId()));
// docs
result.andDo(document("계정 등록",
getDocumentRequest(),
getDocumentResponse(),
requestFields(
fieldWithPath("login_id").type(JsonFieldType.STRING).description("계정 로그인 ID"),
fieldWithPath("password").type(JsonFieldType.STRING).description("계정 비밀번호"),
fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("phone").type(JsonFieldType.STRING).description("전화번호"),
fieldWithPath("birthday").type(JsonFieldType.STRING).description("생년월일").optional(),
fieldWithPath("allow_to_marketing_notification").type(JsonFieldType.BOOLEAN).description("마케팅 정보 수신 동의 여부")
),
responseFields(
fieldWithPath("id").type(JsonFieldType.NUMBER).description("계정 일련번호"),
fieldWithPath("login_id").type(JsonFieldType.STRING).description("계정 로그인 ID")
)));
}
이제 훨씬 보기가 깔끔하다. 중요한 점은 mockMvc.perform() 메서드는 ResultActions를 반환한다는 것이다. 반환된 ResultActions로 검증과 documentation을 분리했다.
즉, 컨트롤러 테스트 부를 아래 4개의 영역으로 나누면서 가독성을 향상시킬 수 있었다.
- given
- when
- then
- (docs)
관련 commit은 아래 링크에서 확인할 수 있다.
'Server > JUnit, Spock' 카테고리의 다른 글
JUnit - Enum으로 Test Fixture 사용하기! (feat. Object Mother, Test Data Builder) (0) | 2022.09.16 |
---|---|
JPA - TestEntityManager를 활용한 Repository 테스트 (0) | 2022.09.14 |
JUnit5 - Nested Class를 사용해서 우아하게 서비스 테스트 작성하기! (0) | 2022.09.03 |
CQRS에서 조회 모델으로 DDL을 생성하는 이슈 해결! (0) | 2022.08.29 |
Java - Spock으로 BDD 테스트하기! (JUnit 대체) (0) | 2022.08.25 |