단위 테스트의 경우
:일반적으로 특정 모듈이나 계층, 기술에 의존적이지 않도록 작성하는 것이 좋음
하나의 애플리케이션은 계층별로 역할이 있고, 계층별로 서로 연동되기 때문에
각각의 계층별로 잘 활동하는지 테스트를 진행해야 함
마지막에는 통합 테스트를 통해 계층 간의 연동에 문제가 없는지 확인해야 테스트 작업이 마무리 됨
슬라이스 테스트Slice Test
:각 계층에 구현해 놓은 기능들이 잘 작동하는지 특정 계층만 잘라서Slice 테스트 하는 것
API 계층 테스트 대상
:대부분 클라이언트의 요청을 받아들이는 핸들러인 Controller임
controller 테스트를 위한 테스트 클래스 구조
postMember() 핸들러 메서드 테스트
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.test.web.servlet.MockMvc;
@SpringBootTest // 1)
@AutoConfigureMockMvc // 2)
public class ControllerTestDefaultStructure {
// 3)
@Autowired
private MockMvc mockMvc;
// 4)
@Test
public void postMemberTest() {
// given 5) 테스트용 request body 생성
// when 6) MockMvc 객체로 테스트 대상 Controller 호출
// then 7) Controller 핸들러 메서드에서 응답으로 수신한 HTTP Status 및 response body 검증
}
}
1) @SpringBootTest
:Spring Boot 기반의 애플리케이션을 테스트하기 위한 Application Context를 생성
(Application Context에는 애플리케이션에 필요한 Bean 객체들이 등록되어 있음)
2) @AutoConfigureMockMvc
:Controller 테스트를 위한 애플리케이션의 자동 구성 작업을 함
:3) MockMvc 기능 사용하려면 @AutoConfigureMockMvc 애너테이션 추가해야 함
3) private MockMvc mockMvc
:DI로 주입받은 MockMvc는 Tomcat 같은 서버를 실행하지 않고
Spring 기반 애플리케이션의 Controller를 테스트 할 수 있는 완벽한 환경을 지원해주는 Spring MVC 테스트 프레임워크임
import com.codestates.member.dto.MemberDto;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.header;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
@Test
void postMemberTest() throws Exception {
// given 1)
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
"홍길동",
"010-1234-5678");
String content = gson.toJson(post); // 2)
// when
ResultActions actions =
mockMvc.perform( // 3)
post("/v11/members") // 4)
.accept(MediaType.APPLICATION_JSON) // 5)
.contentType(MediaType.APPLICATION_JSON) // 6)
.content(content) // 7)
);
// then
actions
.andExpect(status().isCreated()) // 8)
.andExpect(header().string("Location", is(startsWith("/v11/members/")))); // 9)
}
}
1) 2)
//given
MemberDto.Post post = new MemberDteo.post("hgd@gmail.com","홍길동","010-1234-5678")
String content = gson.toJson(post);
:Postman 사용할 때 request body에 포함시키는 요청 데이터와 동일한 역할을 함
:Gson이라는 JSON 변환 라이브러리를 이용해 1)에서 생성한 MemberDto.Post post 객체를 JSON 포맷으로 변환
(Gson 라이브러리를 사용하기 위해서는
build.gradle에 아래 내용을 추가해야 함
dependencies{
implementation 'com.google.code.gson:gson'
}
)
3) 4) 5) 6) 7)
//when
ResultActions actions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON) .content(content)
);
:MockMvc로 테스트 대상 Controller의 핸들러 메서드에 요청을 전송하기 위해서는
기본적으로 perform()
메서드를 호출해야하고
perform()
메서드 내부에 Controller 호출을 위한 세부적인 정보들이 포함됨
:4)post()
:HTTP POST METHOD와 request URL을 설정
:5)accept()
:클라이언트 쪽에서 리턴받을 응답 데이터 타입으로 JSON 타입을 설정<노이해중>
:6)contentType()
:서버쪽에서 처리 가능한 Content Type으로 JSON 타입을 설정<노이해중>
:7)content()
: request body 데이터를 설정
:request body에 전달하는 데이터는 2)에서 Gson 라이브러리를 이용해 변환된 JSON 문자열임
8) 9)
//then
actions
.andExpect(status().isCreated())
.andExpect(header().string("Location", is(startsWith("/v11/members/"))));
:MockMvc의 perform() 메서드는 ResultActions 타입의 객체를 리턴함
:이 ResultAtions 객체를 이용해 전송한 request에 대한 검증을 수행할 수 있음<노이해중>
:8)andExpect()
:파라미터로 입력한 매쳐Matcher로 예상되는 기대 결과를 검증할 수 있음, status().isCreated()
를 통해 response status가 201Created인지 매치시킴
:9)header().string("Location",isstartsWith("/v11/members/"))
:HTTP 헤더에 추가된 Location의 문자열 값이 "/v11/members/"
로 시작하는지 검증
getMember() 핸들러 메서드 테스트
import com.codestates.member.dto.MemberDto;
import com.google.gson.Gson;
import org.junit.jupiter.api.Test;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.http.MediaType;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.ResultActions;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.util.UriComponentsBuilder;
import java.net.URI;
import static org.hamcrest.Matchers.is;
import static org.hamcrest.Matchers.startsWith;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
...
...
@Test
void getMemberTest() throws Exception {
// ===== 1) postMember()를 이용한 테스트 데이터 생성 시작
// given
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com","홍길동","010-1111-1111");
String postContent = gson.toJson(post);
ResultActions postActions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(postContent)
);
// ===== 1) postMember()를 이용한 테스트 데이터 생성 끝
// 2)
String location = postActions.andReturn().getResponse().getHeader("Location"); // "/v11/members/1"
// when / then
mockMvc.perform(
get(location) // 3)
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk()) // 4)
.andExpect(jsonPath("$.data.email").value(post.getEmail())) // 5)
.andExpect(jsonPath("$.data.name").value(post.getName())) // 6)
.andExpect(jsonPath("$.data.phone").value(post.getPhone())); // (7)
}
}
:1) 2)
//1
// given
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com","홍길동","010-1111-1111");
String postContent = gson.toJson(post);
ResultActions postActions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(postContent)
);
//2)
String location = postActions.andReturn().getResponse().getHeader("Location");
:1) postMember() 핸들러 메서드 테스트할 때와 동일
:2) postMember()의 response에 전달되는 Location header 값을 가져오는 로직
:postActions.andReturn().getResponse().getHeader("Location")으로 접근해서 Location header 값을 얻을 수 있음