간단하게 작성할 수 있는 게시판 Controller에 대한 테스트코드입니다.
테스트코드 추가하기
컨트롤러에서 cmd + shift + t
(윈도우는 control + shift + t
)를 누르시면 간단하게 테스트코드를 만들 수 있습니다.
Build.gradle
아래의 의존성을 주입되어있는지 확인해줍니다.
testImplementation 'org.springframework.boot:spring-boot-starter-test'
testImplementation 'org.springframework.security:spring-security-test'
어노테이션
@ExtendWith(SpringExtension.class)
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
class BoardControllerTest {
...
}
- @ExtendWith(SpringExtension.class)
- Spring TestContext Framework를 Junit5에 포함시킬 수 있습니다.
- @SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.MOCK)
- @SpringBootTest 의 webEnvironment 는 기본적으로 SpringBootTest.WebEnvironment.MOCK 으로 설정되어 있습니다. 내장 톰캣을 구동하지 않고 임의로 빈을 만들어 테스트를 한다는 의미입니다.
테스트코드
MockMvc mockMvc;
@Autowired
BoardRepository boardRepository;
private ObjectMapper objectMapper = new ObjectMapper();
@Autowired
private WebApplicationContext wac;
@BeforeEach
public void setup() {
this.mockMvc = MockMvcBuilders.webAppContextSetup(wac)
.addFilter(new CharacterEncodingFilter("UTF-8", true))
.apply(SecurityMockMvcConfigurers.springSecurity())
.build();
}
- @BeforeEach
- TestCode를 실행하기 전에 미리 실행합니다.
- Spring이 주입한 모든 객체를 사용합니다.
- 시큐리티에 대한 설정도 추가합니다.
- ObjectMapper
- Text Json을 오브젝트로, 혹은 오브젝트를 Text Json으로 변경해줍니다.
- 요청이 오면 Content-Type이 json인 것을 Object로 바꿔주고 처리 후 Object를 json으로 변경하여 request 합니다.
게시글 조회
@Test
@DisplayName("게시글 전체 조회 Test")
@WithMockUser
public void 게시글_전체_조회() throws Exception{
this.mockMvc
.perform(get("/api/v1/board"))
.andExpect(status().isOk())
.andDo(print());
}
@Test
@DisplayName("게시글 전체 조회 실패 Test")
public void 게시글_전체_조회_실패() throws Exception{
this.mockMvc
.perform(get("/api/v1/board"))
.andExpect(status().is4xxClientError())
.andDo(print());
}
게시글 작성
@Test
@DisplayName("게시글 작성 Test")
@WithMockUser(roles = "GUEST")
public void 게시글_작성() throws Exception {
BoardDto boardDto = new BoardDto();
boardDto.setAuthor("작성자");
boardDto.setContent("내용");
boardDto.setTitle("제목");
this.mockMvc
.perform(post("/api/v1/board")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(boardDto))
)
.andExpect(status().isOk())
.andDo(print());
}
@Test
@DisplayName("게시글 작성 실패 Test")
public void 게시글_작성_실패() throws Exception {
BoardDto boardDto = new BoardDto();
boardDto.setAuthor("작성자");
boardDto.setContent("내용");
boardDto.setTitle("제목");
this.mockMvc
.perform(post("/api/v1/board")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(boardDto))
)
.andExpect(status().is4xxClientError())
.andDo(print());
}
게시글 수정
@Test
@DisplayName("게시글 수정 Test")
@WithMockUser(roles = "GUEST")
public void 게시글_수정() throws Exception{
Map<String, String> input = new HashMap<>();
input.put("content", "수정된 게시글");
input.put("title", "수정된 제목");
mockMvc.perform(put("/api/v1/board/2")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(input)))
.andExpect(status().isOk())
.andDo(print());
}
@Test
@DisplayName("게시글 수정 실패 Test")
public void 게시글_수정_실패() throws Exception{
Map<String, String> input = new HashMap<>();
input.put("content", "수정된 게시글");
input.put("title", "수정된 제목");
this.mockMvc
.perform(put("/api/v1/board/100")
.contentType(MediaType.APPLICATION_JSON)
.content(objectMapper.writeValueAsString(input)))
.andExpect(status().is4xxClientError())
.andDo(print());
}
게시글 삭제
@Test
@DisplayName("게시글 삭제 Test")
@WithMockUser(roles = "GUEST")
public void 게시글_삭제() throws Exception{
Board board = Board.builder()
.author("작성자")
.title("제목")
.content("본문")
.build();
boardRepository.save(board);
this.mockMvc
.perform(delete("/api/v1/board/1"))
.andExpect(status().isOk())
.andDo(print());
}
@Test
@DisplayName("게시글 삭제 실패 Test")
public void 게시글_삭제_실패() throws Exception{
this.mockMvc
.perform(delete("/api/v1/board/100"))
.andExpect(status().is4xxClientError())
.andDo(print());
}
mockMvc.perform에서 Test하는 HTTP메소드와 경로를 입력하고 status의 상태가 설정한 상태와 같다면 테스트를 통과시킵니다.
각 유닛Test끼리 사이드이팩트가 발생하지 않도록 잘 고려해서 작성해야 합니다.