모든 개발에는 서비스 전에 통합 테스트를 해봐야한다.
1️⃣ 로컬테스트
- 개발이 다 완료 되었다면 본인의 컴퓨터로 모든 것을 테스트 해봐야한다. 모든 기능이 정상 작동을 한다면 서버에서 테스트를 해야한다.
2️⃣ 서버테스트
1.서비스가 환경 세팅
서비스를 하기 위해서는 현재 우리가 개발한 컴퓨터로는 서비스를 하지 못한다. 서비스가 가능한 컴퓨터는 필수 조건이 2가지가 있다.
- 공인IP - 사용자들이 인터넷에서 직접 접근 가능한 IP 주소이다. 공인 IP는 개인 컴퓨터에는 없고 공유기에 공인 IP가 있기 때문에 개인 컴퓨터로는 서비스를 할 수 없다
- 고정IP - 컴퓨터나 장치가 재시작되거나 시간이 지나도 IP가 일정한 주소가 필요하다.
필수 조건이 2가지가 있다면 권장하는 2가지의 조건도 있다.
- 무료 OS - 유료 OS를 쓰게 되면 라이선스 비용이 많이 든다. 이후 유지 보수 등 업데이트로 인해서 계약 비용도 들 수 있기 때문에 무료 OS의 사용을 권장한다. (예시로 Linux가 있다.)
- CLI 환경
-
CLI환경
이란 사용자가 키보드로 명령어만을 입력해서 컴퓨터를 조작하는 것이다. 마우스로 폴더를 더블 클릭이라던지, 우클릭 이런 것이 없는것이다. 그래픽 아이콘과 화면을 이용하는것은GUI환경
이다.CLI환경
을 사용 할 시에는 자원 사용량이 적어서,GUI
보다 효율적이다.GUI
와CLI
가 같은 컴퓨터를 활용 할 때에GUI
는 100 중 50 정도는 그래픽을 담당하기 때문에 50 정도 밖에 리소스를 사용하지 못한다. 하지만CLI
는 100 중 10~20정도만 사용하기 때문에 더욱 많은 리소스를 사용할 수있다.
2. 서비스 서버
서비스가 가능한 컴퓨터가 생겼다면 우리는 이제 로컬 테스트를 끝마친 코드를 서비스컴퓨터에 코드를 옮겨서 테스트 해봐야한다. 서비스 컴퓨터와 로컬 컴퓨터와의 환경이 다르기 때문에 많은 오류가 생길 것이다. 서비스컴퓨터에서 테스트를 할 때에 많은 어려움이 있는데 그 중 2가지를 알아보겠다.
- POSTMAN으로 테스트가 힘들다.
- 우리는 RestAPI를 이용하여 만들었기 때문에 화면이 없다. 즉 화면의 버튼을 클릭하면서 테스트를 해 볼 수 없다는 것이다. 그렇다면 POSTMAN을 이용하여 직접 URL을 입력하고 해야하는데, 만약 오류가 날 경우에는 우리는 이 서버에서 바로 고칠 수 있는 것이 아니라, 로컬 컴퓨터에서 고치고 이후 다시 서비스컴퓨터로 코드를 옮겨야한다.
- 기존 테스트가 끝나고 서비스 중에 업데이트 사항이 생겼을 경우
- 테스트가 모두 끝나고 서비스를 하고 있었다. 하지만 우리는 여기서 계속 멈춰 있는게 아니고 더 좋은 앱, 웹을 위하여 업데이트를 해야한다. 더 좋은 기능을 개발하여 업데이트를 해야하는데, 업데이트를 하려면 서비스를 잠시 중단시키고, 업데이트를 해줘야한다. 이러한 서비스 중단을 방지해야한다.
위 2가지를 해결하기 위해서는 우리는 로컬컴퓨터에서 통합테스트 코드를 만들 것이다.

3️⃣ 테스트 코드
1. 테스트 코드를 사용하는 이유
로컬 서버에서는 잘 돌아가지만 서비스 서버에서는 서로 다른 환경에서 실행하는 것이기 때문에, 서비스 서버에서 정상 작동이 되지 않을 수 있다. 그리고 서비스 서버가 1개가 아니라 무수히 많을 경우에는 무수히 많은 서버를 하나 하나 테스트 해봐야한다. 그러하면 시간이 너무 오래걸린다.
하지만 테스트 코드를 사용하게 되면 각 서버에 빌드 될 때 자동으로 테스트 코드를 실행하고, 테스트 코드에서 오류가 있으면 빌드를 중단한다. 오류가 없으면 정상 작동을 한다는 것이기 때문에 알아서 빌드 된다. 이렇게 테스트 코드를 이용하면 오류가 있으면 ‘아! 오류가 있구나’ 하면서 서비스 서버를 원복 시키지 않고 바로 로컬 컴퓨터에서 테스트 코드만 수정하면 된다.
2. 테스트 코드
- 가짜 환경을 띄우는 어노테이션
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
- 가짜 환경을 실행 해볼 수 있는 어노테이션
@AutoConfigureMockMvc
- 모든 테스트는 테스트가 끝나면 롤백이 된다.
- 재활용이 가능한 함수여도 의존하는게 많은 경우에는 독립적으로 만드는게 좋다. 독립적으로 만들지 않으면 하나의 함수를 고치면 의존하는 모든 것들도 고쳐야 하기 때문이다.
- JSON의 가장 최상의 객체는
$
로 표현한다.jsonPath()
에서$
를 사용하여 꺼내 볼 수 있다.
@AutoConfigureMockMvc // MockMvc 클래스가 IOC로드
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class UserControllerTest {
@Autowired
private ObjectMapper om;
@Autowired
private MockMvc mvc;
@Test
public void join_test() throws Exception {
// given (가짜데이터)
UserRequest.JoinDTO reqDTO = new UserRequest.JoinDTO();
reqDTO.setUsername("haha");
reqDTO.setPassword("1234");
reqDTO.setEmail("haha@nate.com");
String requestBody = om.writeValueAsString(reqDTO); // JAVA 오브젝트를 JSON 오브젝트로 바꿈
// System.out.println(requestBody);
// when (테스트 실행)
ResultActions actions = mvc.perform( // Exception으로 미리 알려주는 에러를 잡음
MockMvcRequestBuilders.post("/join").content(requestBody).contentType(MediaType.APPLICATION_JSON)
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(4));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("haha"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.email").value("haha@nate.com"));
}
}
테스트 결과



4️⃣통합테스트
각각의 함수들을 전부 테스트를 해보았다면 이제는 이것을 한 번에 테스트를 해보아야 한다.
- 통합테스트 방법
- 테스트클래스가 모여있는 파일 또는 test 파일을 우클릭하여 RUN

통합테스트를 하는 이유는 각자 따로 실행했을 때에는 전부 오류가 없이 실행 되지만, 순서에 따라서 통합테스트를 할 경우에 오류가 날 수 있다.
예시로는 BoardController에서 똑같으 boardId가 20인 게시글을 조회하고 수정을 할 것 인데, 수정이 먼저 되버리면 boardId가 20인 게시글을 조회하게 되면 수정된 게시글이 조회되기 때문에 코드로 검증하는 과정에서 오류가 난다.
어노테이션
@Order
을 이용하여서 테스트 코드가 실행되는 순서를 정할 수도 있다. 하지만 이 방법은 좋지 않다. 왜냐하면 테스트의 원칙 중 하나는 독립성인데, 순서에 의존해버리면 독립성이 위배된다. 이후 여러가지 이유도 있다. 유지보수가 어렵고, 병렬 실행이 어려워진다. 또 실제 운영 환경과의 괴리가 생긴다. 그래서 순서의 의존하지 않고 테스트를 짜야한다.그럼 어떻게 해야하냐? 데이터가 추가가 되거나, 수정되거나 한 것을 테스트가 끝나는 즉시 롤백 시키는 것이다. 테스트가 끝났을 때 롤백을 하면 다른 테스트에는 영향을 끼치지 않는다.
테스트가 끝났을 때 롤백을 하는 방법도 여러가지이지만 가장 쉬운
@Transactional
이다.
해당 어노테이션만 붙이면 테스트가 끝날 때 바로 롤백을 해주기 때문에 순서에 의존하지 않고 테스트를 할 수 있다.5️⃣최종 테스트코드
1. UserController 테스트
package shop.mtcoding.blog.integre;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import shop.mtcoding.blog._core.util.JwtUtil;
import shop.mtcoding.blog.user.User;
import shop.mtcoding.blog.user.UserRequest;
import static org.hamcrest.Matchers.matchesPattern;
// 컨트롤러 통합 테스트
@Transactional
@AutoConfigureMockMvc // MockMvc 클래스가 IoC에 로드 | RestTemplate -> 자바스크립트의 fetch와 동일, 진짜 환경에 요청 가능
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK) // MOCK -> 가짜 환경을 만들어 필요한 의존관계를 다 메모리에 올려서 테스트
public class UserControllerTest {
@Autowired
private ObjectMapper om; // json <-> java Object 변환 해주는 객체. IoC에 objectMapper가 이미 떠있음
@Autowired
private MockMvc mvc; // 가짜 환경에서 fetch 요청하는 클래스 | RestTemplate -> 자바스크립트의 fetch와 동일, 진짜 환경에 요청 가능
private String accessToken;
@BeforeEach
public void setUp() {
// 테스트 시작 전에 실행할 코드
System.out.println("setUp");
User ssar = User.builder()
.id(1)
.username("ssar")
.build();
accessToken = JwtUtil.create(ssar);
}
@AfterEach
public void tearDown() { // 끝나고 나서 마무리 함수
// 테스트 후 정리할 코드
System.out.println("tearDown");
}
@Test
public void join_test() throws Exception { // 이 메서드를 호출한 주체에게 예외 위임 -> 지금은 jvm 이다
// given -> 가짜 데이터
UserRequest.JoinDTO reqDTO = new UserRequest.JoinDTO();
reqDTO.setEmail("haha@nate.com");
reqDTO.setPassword("1234");
reqDTO.setUsername("haha");
String requestBody = om.writeValueAsString(reqDTO);
// System.out.println(requestBody); // {"username":"haha","password":"1234","email":"haha@nate.com"}
// when -> 테스트 실행
ResultActions actions = mvc.perform( // 주소가 틀리면 터지고, json 아닌거 넣으면 터지고, 타입이 달라도 터지고. 따라서 미리 터진다고 알려줌
MockMvcRequestBuilders
.post("/join")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
);
// eye -> 결과 눈으로 검증
String responseBody = actions.andReturn().getResponse().getContentAsString();
//System.out.println(responseBody); // {"status":200,"msg":"성공","body":{"id":4,"username":"haha","email":"haha@nate.com","createdAt":"2025-05-13 11:45:23.604577"}}
// then -> 결과를 코드로 검증 // json의 최상위 객체를 $ 표기한다
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(4));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("haha"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.email").value("haha@nate.com"));
}
@Test
public void login_test() throws Exception {
// given
UserRequest.LoginDTO reqDTO = new UserRequest.LoginDTO();
reqDTO.setUsername("ssar");
reqDTO.setPassword("1234");
String requestBody = om.writeValueAsString(reqDTO);
// System.out.println(requestBody);
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.post("/login")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (jwt 길이만 검증) -> 길이 변환 가능. 패턴만 확인
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.accessToken",
matchesPattern("^[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+\\.[A-Za-z0-9-_]+$")));
}
@Test
public void update_test() throws Exception {
// given
UserRequest.UpdateDTO reqDTO = new UserRequest.UpdateDTO();
reqDTO.setEmail("ssar@gmail.com");
reqDTO.setPassword("1234");
String requestBody = om.writeValueAsString(reqDTO);
// System.out.println(requestBody);
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.put("/s/api/user")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("ssar"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.email").value("ssar@gmail.com"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt",
matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+")));
}
@Test
public void checkUsernameAvailable_test() throws Exception {
// given
String username = "ssar";
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.get("/api/check-username-available/{username}", username)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.available").value(false));
}
}
2. BoardController 테스트
package shop.mtcoding.blog.integre;
import com.fasterxml.jackson.databind.ObjectMapper;
import org.hamcrest.Matchers;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import shop.mtcoding.blog._core.util.JwtUtil;
import shop.mtcoding.blog.board.BoardRequest;
import shop.mtcoding.blog.user.User;
import static org.hamcrest.Matchers.nullValue;
@AutoConfigureMockMvc // MockMvc 클래스가 IOC로드
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class BoardControllerTest {
@Autowired
private ObjectMapper om;
@Autowired
private MockMvc mvc;
private String accessToken;
@BeforeEach // Each = 함수마다 실행됨 | ALL = 한 번만 실행 (static으로 만들어야함 왠만하면 사용 X)
public void setUp() { // 테스트 시작 전에 실행 할 코드
System.out.println("setUp");
User ssar = User.builder().id(1).username("ssar").build();
accessToken = JwtUtil.create(ssar);
}
@AfterEach
public void tearDown() { // 테스트 후 정리 할 코드
System.out.println("tearDown");
}
// 나머지 메서드도 전부 테스트
// 배열은 0번지만 검사
@Test
public void update_test() throws Exception {
// given (가짜데이터)
Integer boardId = 1;
BoardRequest.UpdateDTO reqDTO = new BoardRequest.UpdateDTO();
reqDTO.setTitle("제21");
reqDTO.setContent("내21");
reqDTO.setIsPublic(true);
String requestBody = om.writeValueAsString(reqDTO); // JAVA 오브젝트를 JSON 오브젝트로 바꿈
System.out.println(requestBody);
// when (테스트 실행)
ResultActions actions = mvc.perform( // Exception으로 미리 알려주는 에러를 잡음
MockMvcRequestBuilders
.put("/s/api/board/" + boardId)
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제21"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내21"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value("true"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userID").value("1"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt")
.value(Matchers.matchesPattern("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}$")));
}
@Test
public void BoardOne_test() throws Exception {
// given (가짜데이터)
Integer boardId = 1;
User user = User.builder().id(1).username("ssar").build();
// when (테스트 실행)
ResultActions actions = mvc.perform( // Exception으로 미리 알려주는 에러를 잡음
MockMvcRequestBuilders
.get("/api/board/" + boardId)
.sessionAttr("sessionUser", user)
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목1"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용1"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value("true"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userID").value("1"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt")
.value(Matchers.matchesPattern("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d{6}$")));
}
@Test
public void detail_test() throws Exception {
// given (가짜데이터)
String boardId = "4";
// when (테스트 실행)
ResultActions actions = mvc.perform( // Exception으로 미리 알려주는 에러를 잡음
MockMvcRequestBuilders
.get("/api/board/" + boardId + "/detail")
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(4));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목4"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용4"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value(true)); // true는 boolean 타입이어야 합니다
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isOwner").value(false)); // false는 boolean 타입이어야 합니다
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isLove").value(false)); // false는 boolean 타입이어야 합니다
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(2));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.username").value("love"));
// createdAt 검증
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt")
.value(Matchers.matchesPattern("^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}[+-]\\d{2}:\\d{2}$")));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveId").value(nullValue()));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].id").value(3));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].content").value("댓글3"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].username").value("ssar"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.replies[0].isOwner").value(false));
}
@Test
public void list_test() throws Exception {
// given (가짜데이터)
String page = "1";
String keyword = "제목1";
// when (테스트 실행)
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.get("/")
.param("keyword", keyword)
.param("page", page)
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].id").value(16));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].title").value("제목16"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].content").value("내용16"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].isPublic").value(true));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].userId").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boards[0].createdAt")
.value(Matchers.matchesPattern("^\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+$")));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.prev").value(0));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.next").value(2));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.current").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.size").value(3));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.totalCount").value(11));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.totalPage").value(4));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isFirst").value(false));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isLast").value(false));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.keyword").value("제목1"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.numbers", Matchers.hasSize(4)));
}
@Test
public void save_test() throws Exception {
// given (가짜데이터)
BoardRequest.SaveDTO reqDTO = new BoardRequest.SaveDTO();
reqDTO.setTitle("제목21");
reqDTO.setContent("내용21");
reqDTO.setIsPublic(true);
String requestBody = om.writeValueAsString(reqDTO); // JAVA 오브젝트를 JSON 오브젝트로 바꿈
// System.out.println(requestBody);
// when (테스트 실행)
ResultActions actions = mvc.perform( // Exception으로 미리 알려주는 에러를 잡음
MockMvcRequestBuilders
.post("/s/api/board")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
);
// eye (결과 눈으로 검증)
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then (결과 코드로 검증)
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(21));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.title").value("제목21"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("내용21"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.isPublic").value("true"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userID").value("1"));
}
}
3. ReplyController 테스트
package shop.mtcoding.blog.integre;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import shop.mtcoding.blog._core.util.JwtUtil;
import shop.mtcoding.blog.reply.ReplyRequest;
import shop.mtcoding.blog.user.User;
import static org.hamcrest.Matchers.matchesPattern;
import static org.hamcrest.Matchers.nullValue;
@Transactional
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class ReplyControllerTest {
@Autowired
private ObjectMapper om;
@Autowired
private MockMvc mvc;
private String accessToken;
@BeforeEach
public void setUp() {
// 테스트 시작 전에 실행할 코드
System.out.println("setUp");
User ssar = User.builder()
.id(1)
.username("ssar")
.build();
accessToken = JwtUtil.create(ssar);
}
@AfterEach
public void tearDown() { // 끝나고 나서 마무리 함수
// 테스트 후 정리할 코드
System.out.println("tearDown");
}
@Test
public void save_test() throws Exception {
// given
ReplyRequest.SaveDTO reqDTO = new ReplyRequest.SaveDTO();
reqDTO.setBoardId(1);
reqDTO.setContent("댓글6");
String requestBody = om.writeValueAsString(reqDTO);
System.out.println(requestBody);
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.post("/s/api/reply")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.id").value(6));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.content").value("댓글6"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.userId").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.boardId").value(1));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.createdAt",
matchesPattern("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}\\.\\d+")));
}
@Test
public void delete_test() throws Exception {
// given
Integer id = 1;
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.delete("/s/api/reply/{id}", id)
.header("Authorization", "Bearer " + accessToken)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body").value(nullValue()));
}
}
4.LoveController 테스트
package shop.mtcoding.blog.integre;
import com.fasterxml.jackson.databind.ObjectMapper;
import jakarta.transaction.Transactional;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
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.test.web.servlet.request.MockMvcRequestBuilders;
import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
import shop.mtcoding.blog._core.util.JwtUtil;
import shop.mtcoding.blog.love.LoveRequest;
import shop.mtcoding.blog.user.User;
@Transactional
@AutoConfigureMockMvc
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
public class LoveControllerTest {
@Autowired
private ObjectMapper om;
@Autowired
private MockMvc mvc;
private String accessToken;
@BeforeEach
public void setUp() {
// 테스트 시작 전에 실행할 코드
System.out.println("setUp");
User ssar = User.builder()
.id(1)
.username("ssar")
.build();
accessToken = JwtUtil.create(ssar);
}
@AfterEach
public void tearDown() { // 끝나고 나서 마무리 함수
// 테스트 후 정리할 코드
System.out.println("tearDown");
}
@Test
public void saveLove_test() throws Exception {
// given
LoveRequest.SaveDTO reqDTO = new LoveRequest.SaveDTO();
reqDTO.setBoardId(3);
String requestBody = om.writeValueAsString(reqDTO);
// System.out.println(requestBody);
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.post("/s/api/love")
.content(requestBody)
.contentType(MediaType.APPLICATION_JSON)
.header("Authorization", "Bearer " + accessToken)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveId").value(4));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(1));
}
@Test
public void deleteLove_test() throws Exception {
// given
Integer id = 1;
// when
ResultActions actions = mvc.perform(
MockMvcRequestBuilders
.delete("/s/api/love/{id}", id)
.header("Authorization", "Bearer " + accessToken)
);
// eye
String responseBody = actions.andReturn().getResponse().getContentAsString();
System.out.println(responseBody);
// then
actions.andExpect(MockMvcResultMatchers.jsonPath("$.status").value(200));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.msg").value("성공"));
actions.andExpect(MockMvcResultMatchers.jsonPath("$.body.loveCount").value(0));
}
}
Share article