JUnit Test의 목적
#1. 테스트 메서드에서 나오는 Dto.ResponseDto 객체의 필드 값들과,
테스트 메서드의 URL을 향한 HTTP 요청에 대한 응답 데이터 (ResultActions) 의 필드 값이 일치하는지 검증
[Dto.Response 객체]
특정 Controller 메서드에 대한 HTTP 요청의 예상되는 결과 데이터를 나타낸다.
HTTP는 텍스트 기반 프로토콜이고 Controller 메서드의 결과는 Java 객체의 형태를 띄기 때문에
Dto.Response 데이터는 서버에서 클라이언트로 전달되기 전에 JSON 형태로 변환된다.
[ResultActions 객체]
MockMvc의 perform() 메서드를 통해
특정 Controller 메서드의 URL로 mock HTTP 요청을 보냇을 때의 응답을 나타낸다.
이 객체는 HTTP 요청에 대한 실제 응답 결과이다.
즉, Dto.Response 객체는 Controller 메서드로 HTTP 요청을 했을 때 예상되는 결과를,
ResultActions 객체는 Controller 메서드로 HTTP 요청을 했을 때 실제 결과를 나타내며,
이 둘 사이의 일치 여부를 통해 테스트의 성공/실패를 판단한다.
[요약]
Dto.ResponseDto = ResultActions ? JUnit Passed : JUnit no Passed
#2. 작성한 메서드들의 API 명세서를 자동 생성하는 것.
JUnit Test 메서드 작성 Tip
1. 대상 메서드의 본연의 기능이 잘 되는지 확인이 주목적.
2. 대상 메서드에서 사용된 모든 객체의 메서드를 사용한다.
3. 설정해둔 예외 발생 조건은 모두 발생하지 않는다는 가정을 전제로 한다.
JUnit Test에서 사용되는 애너테이션
1. 클래스 레벨 애너테이션
@WebMvcTest(MemberController.class)
@AutoConfigureRestDocs
@AutoConfigureMockMvc(addFilters = false)
public class MemberControllerTest {
2. 필드 레벨 애너테이션
A. @Autowired : MockMvc, Gson
B. @MockBean : 대상 클래스에서 사용된 모든 Bean 객체들.
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
@MockBean
private MemberRepository memberRepository;
@MockBean
private MemberBookRepository memberBookRepository;
@MockBean
private MemberBookService memberBookService;
@MockBean
private MemberMapper memberMapper;
@MockBean
private MemberService memberService;
@MockBean
private LibraryService libraryService;
@MockBean
private LibraryMemberRepository libraryMemberRepository;
@MockBean
private LibraryMemberService libraryMemberService;
@MockBean
private MemberBookMapper memberBookMapper;
3. 메서드 레벨 애너테이션
@Test
@Test
public void postMember() throws Exception {
4. Testing에 사용되는 메서드
1. given().willReturn();
테스트 대상 메서드에서 사용된 메서드를 실제 대상이 아닌 Mock 객체로써 동작하도록 하는 것.
>> given( 메서드가 속한 객체 . 실행 메서드 (Mockito.any(실행_메서드_파라미터_타입.class)))
.willReturn(실행_메서드_반환타입);
given(memberMapper.memberDtoPostToMember(any(MemberDto.Post.class))).willReturn(new Member());
2. String 변수명 = gson.toJson(DTO변수);
요청에 해당하는 DTO 객체를 Json 형식인 StringType으로 변환하는 메서드.
String content = gson.toJson(post);
3. ResultActions actions = mockMvc.perform()
요청에 대한 응답 데이터의 타입인 ResultActions 선언.
ResultActions actions =
mockMvc.perform(
RestDocumentationRequestBuilders.post("/members/{libraryId}",libraryId)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
4. mockMvc.perform() : 요청 전송을 담당. 즉, 요청을 보낼꺼야 ~ 라는 의미.
해당 메서드는 입력된 url로 mock HTTP 요청을 보내고,
ResultActions는 perform() 메서드로 보낸 요청의 결과를 담음.
5. perform() 안 RestDocumentationRequestBuilders.post/patch/get/delete("url")
: 요청이 도착할 url과 HttpMethod 종류.
6. .accept(MediaType.APPLICATION_JSON)
: 요청에 대한 응답 데이터의 타입을 Json 으로 설정하겠다는 의미
7. .contentType(MediaType.APPLICATION_JSON)
: 요청 데이터의 타입을 Json 형식으로 정한다는의미.
8. .content() : 요청(request body)에 해당하는 데이터를 Json 형식으로 바꾼 객체를 파라미터로 전달.
9. actions. : 응답 데이터의 타입은 ResultActions 타입의 객체에 대한 설정.
actions
.andExpect(status().isCreated())
.andExpect(jsonPath("$.name").value(response.getName()))
.andDo(document(
"post-member",
getRequestPreProcessor(),
getResponsePreProcessor(),
pathParameters(
parameterWithName("libraryId").description("도서관 식별자")
),
requestParameters(
parameterWithName("page").description("내용이 나오는 페이지"),
parameterWithName("size").description("한 페이지에 나오는 최대 갯수")
),
requestFields(
List.of(
fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호"),
fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
fieldWithPath("password").type(JsonFieldType.STRING).description("비밀번호")
)
),
responseFields(
List.of(
fieldWithPath("memberId").type(JsonFieldType.NUMBER).description("회원 식별자"),
fieldWithPath("libraryId").type(JsonFieldType.NUMBER).description("도서관 식별자"),
fieldWithPath("name").type(JsonFieldType.STRING).description("이름"),
fieldWithPath("phone").type(JsonFieldType.STRING).description("휴대폰 번호"),
fieldWithPath("email").type(JsonFieldType.STRING).description("이메일"),
fieldWithPath("password").type(JsonFieldType.STRING).description("비밀번호"),
fieldWithPath("url").type(JsonFieldType.STRING).description("조회 URL")
)
)
));
A. .andExpect() : 응답 데이터 내용에 대한 예상 값.
1. status().isCreated() : 응답 데이터의 응답 상태가 isCreated() 라고 예상.
2. jsonPath("$.name").value(response.getName())) :
대상 메서드로 HTTP 요청의 실제 결과 값인 actions 값과
대상 메서드로의 요청에 대해 우리가 예상하는 결과 데이터인 Dto.Response 객체가
서로 같은 값인지 확인.
jsonPath()를 통해 전달한 필드 값이 value() 안에 포함된 요청에 대한 예상 결과 값과 같은지 비교.
jsonPath($.필드명) 은 아래와 같이 실제 응답 데이터의 필드를 뜻한다.
Page의 경우 jsonPath($.data[0].필드명)를 사용하는데
Multi-Response은 데이터를 data[i] 로 관리하므로 위의 사진속 전체 데이터가 data[0]에 포함된다.
3. andDo(document("post-member"))
: Spring RestDocs의 문서 작성 메서드이자, RESTful 서비스의 문서 작성 명령문.
"post-member" 문구는 해당 테스트에서 생성되는 문서의 식별자 역할.
즉, .andDo(document("delete-member")) 라고 사용하게되면,
Spring RestDocs의 API 명세서를 작성하는데 delete-member 메서드에 대한 문서라는 뜻.
4. getRequestPreProcessor(), getResponsePreProcessor()
: 출력을 이쁘게 해주는 인터페이스 메서드. 초기에 생성하는 인터페이스이다.
5. pathParameters(parameterWithName("libraryId").description("도서관 식별자")
: 요청을 보내는 URL에 포함된 파라미터가 있을 경우,
자동 생성된 API 문서에서 해당 파라미터가 어떤 것을 나타내는지 설명.
6. requestParameters(parameterWithName().description())
: 메서드로 보내는 요청안에 전달하는 Param이 있을 경우, 해당 요소들에 대한 정보를 전달.
7. request/responseFields(List.of(fieldWithPath("요청/응답데이터의 필드명")
.type(JsonFieldType.필드타입).description("어떤 필드인지 설명"));
fieldWithPath() : 요청/응답 데이터에 있는 필드명.
type(JsonFieldType.{}) : 요청 데이터에 있는 필드들의 데이터 타입.
description() : 요청 데이터에 있는 필드들의 의미.
'Tips' 카테고리의 다른 글
JMeter 설치 & 사용 법 (0) | 2023.05.25 |
---|---|
QueryDsl 메서드 모음 (0) | 2023.05.23 |
Spring Data JPA VS JPQL and QueryDsl (0) | 2023.05.15 |
Mapstruct @Mapping(target = , source = ) (0) | 2023.05.13 |
Spring Data JPA - 자동 완성 메서드 규칙 (0) | 2023.05.12 |