Spring RestDocs 작성 가이드 #2 응용편 - 보일러플레이트 코드 제거
728x90
반응형
Github: https://github.com/syakuis/spring-restdocs
RestDocs 는 여러 컨트롤러에서 만들어지는 중복되는 필드 정의에 의해 생산성이 저하될 수 있다.
AS-IS
TO-BE
AS-IS 에서 표시된 영역에서 반복이 발생되어 모듈로 만들어 재사용할 수 있도록 TO-BE 와 같이 구현할 것이다.
그래서 보일러플레이트 코드를 제거하고 한번 정의된 필드를 재사용할 수 있는 방법을 가이드하였다.
사용 가이드
클래스 설명
- Descriptor : RestDocs 사용에 맞춰 필드를 정의하는 인터페이스이다.
- RestDocsDescriptor : 정의된 필드를 제어한다.
- AutoConfigureMvcRestDocs : 현 API 초기 설정을 정의한 RestDocs 설정한다.
필드 정의 예시
[코드 1-1] enum 에서 필드 정의
@Getter
public enum ChangePasswordField implements Descriptor {
currentPassword("현재 비밀번호", false),
newPassword("새로운 비밀번호", false),
newPasswordConfirm("새로운 비밀번호 확인", false);
private final String description;
private final boolean optional;
ChangePasswordField(String description, boolean optional) {
this.description = description;
this.optional = optional;
}
}
테스트 작성시 아래와 같이 선언해주어야 한다.
private final RestDocsDescriptor changePasswordFieldHandler = new RestDocsDescriptor(ChangePasswordField.values());
위와 같이 하면 필드 정의는 끝났다.
테스트 작성
항목 정의 기능
- RestDocsDescriptor.of(Descriptor... field) : 정의할 필드를 입력한다. 입력하지 않으면 전체를 필드를 정의한다.
최종 완료 기능
- RestDocsDescriptor.exclude(Descriptor.... field) : payload 에 제외한 필드를 정의한다.
- RestDocsDescriptor.stream() : java stream 을 반환한다. Stream
- RestDocsDescriptor.collect(DescriptorCollectors::xxxDescriptor) : RestDocs 에서 사용할 수 있도록 리스트로 반환한다.
- DescriptorCollectors::headerDescriptor
- DescriptorCollectors::linkDescriptor
- DescriptorCollectors::fieldDescriptor
- DescriptorCollectors::requestPartDescriptor
- DescriptorCollectors::parameterDescriptor
예시 코드
@ExtendWith(SpringExtension.class)
@SpringBootTest
@AutoConfigureMockMvc
@AutoConfigureMvcRestDocs
class AuthenticatedAccountRestControllerTest {
@Autowired
private MockMvc mvc;
@Autowired
private ObjectMapper mapper;
private final RestDocsDescriptor changePasswordFieldHandler = new RestDocsDescriptor(ChangePasswordField.values());
private String pathPrefix;
private String restdocsPath;
@BeforeEach
void init() {
pathPrefix = "/v1/me";
restdocsPath = "accounts/v1/me/{method-name}";
}
@Test
void changePassword() throws Exception {
AccountRequestDto.ChangePassword changePassword = AccountRequestDto.ChangePassword.builder()
.currentPassword("1234")
.newPassword("aaaa")
.newPasswordConfirm("aaaa")
.build();
mvc.perform(patch(pathPrefix + "/password")
.content(mapper.writeValueAsString(changePassword))
.contentType(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andDo(document(restdocsPath,
requestHeaders(
headerWithName(HttpHeaders.CONTENT_TYPE).description(MediaType.APPLICATION_JSON)
),
requestFields(
changePasswordFieldHandler.of(ChangePasswordField.currentPassword, ChangePasswordField.newPassword, ChangePasswordField.newPasswordConfirm)
.collect(DescriptorCollectors::fieldDescriptor)
)
));
}
}
그외 사용 예시 참고
- https://github.com/syakuis/spring-restdocs/blob/master/src/test/java/io/github/syakuis/restdocs/DescriptorCollectorTest.java
- https://github.com/syakuis/spring-restdocs/blob/master/src/test/java/io/github/syakuis/restdocs/RestDocsDescriptorTest.java
추가적인 이슈
필드가 추가되거나 변경될 경우 모든 페이지에 수정작업이 발생된다.
하여 필드를 정의하는 enum 구현에서 정적 메서드로 명시적인 필드를 제공하는 것이 효율적일 수 있다.
코드 1-1 을 참고하여 아래와 같이 작성할 수 있다.
@Getter
public enum AccountField implements FieldSpec {
... skip ...
public static String[] request() {
return new String[]{
AccountField.username,
AccountField.password,
AccountField.name,
AccountField.disabled,
AccountField.blocked
};
}
public static String[] profile() {
return new String[]{
AccountField.uid,
AccountField.username,
AccountField.name,
AccountField.registeredOn,
AccountField.updatedOn
};
}
}
728x90
반응형
'Tech' 카테고리의 다른 글
Java Database Connection TLS 보안 이슈 (0) | 2021.10.07 |
---|---|
QueryDSL for Spring Data JPA (0) | 2021.10.06 |
Spring RestDocs 작성 가이드 #1 기본편 (0) | 2021.09.14 |
Spring MVC Test - Response Body 한글 깨짐 이슈 (0) | 2021.09.12 |