@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 검증
}
}
import static org.hamcrest.Matchers.*;
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.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.assertj.core.api.Assertions.*;
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
private MemberDto.Post post;
private ResultActions postAction;
private String postLocation;
@BeforeEach
void init() throws Exception {
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
"홍길동",
"010-1234-5678");
// (1)
String content = gson.toJson(post);
// (2)
ResultActions actions =
mockMvc.perform( // (3)
post("/v11/members") // (3-1)
.accept(MediaType.APPLICATION_JSON) // (3-2)
.contentType(MediaType.APPLICATION_JSON) // (3-3)
.content(content) // (3-4)
);
// (4)
this.post = post;
this.postAction = actions;
this.postLocation = actions.andReturn().getResponse().getHeader("Location");
}
...
}
(2) ResultActions
(3) mockMvc
perform() 메서드를 호출해 핸들러 메서드에 요청 전송
(3-1) HTTP 메서드와 request URL 설정
(3-2) 요청 형식을 JSON 형식으로 설정 (request의 Accept 헤더 설정)
(3-3) 요청 본문을 JSON 형식으로 설정 (request의 Content-Type 헤더 설정)
(3-4) 요청의 본문에 들어갈 데이터를 지정 (request의 body 설정)
(4) 각 테스트 케이스에서 사용하기 위한 전역변수 지정
@Test
void postMemberTest() throws Exception {
postAction // (1)
.andExpect(status().isCreated()) // (2)
.andExpect(header().string("Location", is(startsWith("/v11/members/")))); // (3)
}
@Test
void patchMemberTest() throws Exception {
// (1)
long memberId = Long.parseLong(postLocation.substring(postLocation.lastIndexOf("/") + 1));
// when patch member (2)
MemberDto.Patch patch = new MemberDto.Patch(
memberId,
"홍길동",
"010-2222-2222"
);
String patchContent = gson.toJson(patch);
ResultActions patchAction =
mockMvc.perform(
patch("/v11/members/" + memberId)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(patchContent)
);
// then (3)
mockMvc.perform(
get("/v11/members/" + memberId)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.name").value(patch.getName()))
.andExpect(jsonPath("$.data.phone").value(patch.getPhone()));
}
@Test
void getMembersTest() throws Exception {
// given 회원 1명 더 등록
MemberDto.Post post2 = new MemberDto.Post(
"hgd@naver.com",
"Gildong",
"010-2222-2222"
);
String postContent2 = gson.toJson(post2);
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(postContent2)
);
// when
int page = 1;
int size = 20;
ResultActions getAction =
mockMvc.perform( // getMembers 요청
get("/v11/members")
.param("page", String.valueOf(page)) // (1)
.param("size", String.valueOf(size))
.accept(MediaType.APPLICATION_JSON));
getAction // (2)
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.[0].email").value(post2.getEmail()))
.andExpect(jsonPath("$.data.[1].email").value(post.getEmail()))
.andExpect(jsonPath("$.data.[0].name").value(post2.getName()))
.andExpect(jsonPath("$.data.[1].name").value(post.getName()))
.andExpect(jsonPath("$.data.[0].phone").value(post2.getPhone()))
.andExpect(jsonPath("$.data.[1].phone").value(post.getPhone()));
}
@Test
void deleteMemberTest() throws Exception {
long memberId = Long.parseLong(postLocation.substring(postLocation.lastIndexOf("/") + 1));
mockMvc.perform(
delete("/v11/members/" + memberId))
.andExpect(status().isNoContent());
}
Spring MVC 프레임워크를 실행하지 않고도 컨트롤러를 테스트 가능
DispatcherServlet을 직접 실행하지 않고 HTTP 요청을 생성
별도의 서버 설정이나 네트워크 연결 없이 컨트롤러에 대한 테스트를 수행
@SpringBootTest와 함께 사용
@AutoConfigureMockMvc 사용하여 MockMvc 객체를 자동으로 구성
메서드
perform() : 핸들러 메서드에 요청 전송
post(),get() 등 : HTTP 메서드와 request URL 설정
accept() : 요청 형식을 JSON 형식으로 설정 (request의 Accept 헤더 설정)
contentType() : 요청 본문을 JSON 형식으로 설정 (request의 Content-Type 헤더 설정)
content() 요청의 본문에 들어갈 데이터를 지정 (request의 body 설정)
ResultActions의 andReturn() 메서드를 통해 반환되는 실제 요청과 응답의 상세 정보를 제공하는 객체
메서드
getResponse()
getRequest()
getResponse().getContentAsString(): 응답 본문을 문자열 형태로 반환
{
"store": {
"book": [
{
"category": "reference",
"author": "Nigel Rees",
"title": "Sayings of the Century",
"price": 8.95
},
{
"category": "fiction",
"author": "Evelyn Waugh",
"title": "Sword of Honour",
"price": 12.99
},
{
"category": "fiction",
"author": "Herman Melville",
"title": "Moby Dick",
"isbn": "0-553-21311-3",
"price": 8.99
},
{
"category": "fiction",
"author": "J. R. R. Tolkien",
"title": "The Lord of the Rings",
"isbn": "0-395-19395-8",
"price": 22.99
}
],
"bicycle": {
"color": "red",
"price": 19.95
}
},
"expensive": 10
}
import static org.hamcrest.Matchers.*;
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.request.MockMvcRequestBuilders.patch;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
import static org.assertj.core.api.Assertions.*;
@Transactional
@SpringBootTest
@AutoConfigureMockMvc
class MemberControllerTest {
@Autowired
private MockMvc mockMvc;
@Autowired
private Gson gson;
private MemberDto.Post post;
private ResultActions postAction;
private String postLocation;
@BeforeEach
void init() throws Exception {
MemberDto.Post post = new MemberDto.Post("hgd@gmail.com",
"홍길동",
"010-1234-5678");
String content = gson.toJson(post);
ResultActions actions =
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(content)
);
this.post = post;
this.postAction = actions;
this.postLocation = actions.andReturn().getResponse().getHeader("Location");
}
@Test
void postMemberTest() throws Exception {
postAction
.andExpect(status().isCreated())
.andExpect(header().string("Location", is(startsWith("/v11/members/"))));
}
@Test
void getMemberTest() throws Exception {
long memberId = Long.parseLong(postLocation.substring(postLocation.lastIndexOf("/") + 1));
mockMvc.perform(
get("/v11/members/" + memberId)
.accept(MediaType.APPLICATION_JSON)
)
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.email").value(post.getEmail()))
.andExpect(jsonPath("$.data.name").value(post.getName()))
.andExpect(jsonPath("$.data.phone").value(post.getPhone()));
}
@Test
void patchMemberTest() throws Exception {
long memberId = Long.parseLong(postLocation.substring(postLocation.lastIndexOf("/") + 1));
MemberDto.Patch patch = new MemberDto.Patch(
memberId,
"홍길동",
"010-2222-2222"
);
String patchContent = gson.toJson(patch);
ResultActions patchAction =
mockMvc.perform(
patch("/v11/members/" + memberId)
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(patchContent)
);
mockMvc.perform(
get("/v11/members/" + memberId)
.accept(MediaType.APPLICATION_JSON))
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.name").value(patch.getName()))
.andExpect(jsonPath("$.data.phone").value(patch.getPhone()));
}
@Test
void getMembersTest() throws Exception {
MemberDto.Post post2 = new MemberDto.Post(
"hgd@naver.com",
"Gildong",
"010-2222-2222"
);
String postContent2 = gson.toJson(post2);
mockMvc.perform(
post("/v11/members")
.accept(MediaType.APPLICATION_JSON)
.contentType(MediaType.APPLICATION_JSON)
.content(postContent2)
);
int page = 1;
int size = 20;
ResultActions getAction =
mockMvc.perform(
get("/v11/members")
.param("page", String.valueOf(page))
.param("size", String.valueOf(size))
.accept(MediaType.APPLICATION_JSON));
getAction
.andExpect(status().isOk())
.andExpect(jsonPath("$.data.[0].email").value(post2.getEmail()))
.andExpect(jsonPath("$.data.[1].email").value(post.getEmail()))
.andExpect(jsonPath("$.data.[0].name").value(post2.getName()))
.andExpect(jsonPath("$.data.[1].name").value(post.getName()))
.andExpect(jsonPath("$.data.[0].phone").value(post2.getPhone()))
.andExpect(jsonPath("$.data.[1].phone").value(post.getPhone()));
}
@Test
void deleteMemberTest() throws Exception {
long memberId = Long.parseLong(postLocation.substring(postLocation.lastIndexOf("/") + 1));
mockMvc.perform(
delete("/v11/members/" + memberId))
.andExpect(status().isNoContent());
}
}