Controller JUnit 테스트할 때의 어노테이션 정리
@ExtendWith(SpringExtension.class) //JUnit5 버전, JUnit5 버전은 @RunWith
- 스프링 부트 테스트와 JUnit 사이에 연결자 역할
@AutoConfigureMockMvc //@WebMvcTest(@Service, @Repository 테스트 불가능, 컨트롤러 테스트만 가능) 비슷한 의미
- MockMvc 제어하는 어노테이션
- @Controller 뿐만 아니라 @Service, @Repository 모두 테스트 가능
@SpringBootTest
- 테스트에 필요한 거의 모든 의존성 제공
- Autowired 허용하여 객체 의존성 주입
- 사용 시 @ExtendWith(SpringExtension.class) 이미 포함하고 있기 때문에 @ExtensionWith을 사용하지 않아도 됨
@Autowired
private MockMvc mvc;
- 스프링이 관리하는 빈(Bean) MockMvc 객체 의존성 주입 받음
- @SpringBootTest 어노테이션이 없다면 의존성 주입이 되지 않아 값이 null로 처리됨
@Test
- 테스트할 메서드
테스트 내용 예시:
@Test
public void hello(){
//given
String hello = "hello";
//when, then
mvc.perform(get("/hello")) //get매핑으로 /hello 요청
.andExpect(status().isOk()) // 200번 OK상태인지 확인
.andExpect(content().string(hello)); //hello 리턴하는지 확인
}
참고소스:
package com.jojoldu.book.springboot.web;
import com.jojoldu.book.springboot.config.auth.SecurityConfig;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.FilterType;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import static org.hamcrest.Matchers.is;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.*;
//@RunWith(SpringRunner.class) // JUnit4 버전
@ExtendWith(SpringExtension.class) //JUnit5 버전
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}
) //웹(컨트롤러)만 테스트 가능 , 서비스or레포지토리 테스트 안됨
public class HelloControllerTest {
@Autowired
private MockMvc mvc; //개발한 웹 프로그램을 실제 서버에 배포하지 않고도 테스트를 위한 요청을 제공 즉, 웹 API 테스트 할 때 사용, 이 클래스를 통해 HTTP GET, POST등에 대한 API테스트
@Test
@WithMockUser(roles = "USER")
public void hello가_리턴된다() throws Exception {
//given
String hello = "hello";
//when, then
mvc.perform(get("/hello")) //get매핑으로 /hello 요청
.andExpect(status().isOk()) // 200번 OK상태인지 확인
.andExpect(content().string(hello)); //hello 리턴하는지 확인
}
//@WithMockUser(roles="USER")
@Test
@WithMockUser(roles = "USER")
public void helloDto가_리턴된다() throws Exception {
//given
String name = "hello";
int amount = 1000;
//when, then
mvc.perform(
get("/hello/dto")
.param("name", name)
.param("amount", String.valueOf(amount)))
.andExpect(status().isOk())
.andExpect(jsonPath("$.name", is(name))) //json 응닫값이 name과 같은지
.andExpect(jsonPath("$.amount", is(amount))); //json 응답값이 amount와 같은지
}
}
package com.jojoldu.book.springboot.web;
import com.jojoldu.book.springboot.web.dto.PostsSaveRequestDto;
import com.fasterxml.jackson.databind.ObjectMapper;
import com.jojoldu.book.springboot.domain.posts.Posts;
import com.jojoldu.book.springboot.domain.posts.PostsRepository;
import com.jojoldu.book.springboot.web.dto.PostsUpdateRequestDto;
import org.junit.jupiter.api.AfterEach;
import org.junit.jupiter.api.BeforeEach;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.boot.test.web.server.LocalServerPort;
import org.springframework.http.*;
import org.springframework.security.test.context.support.WithMockUser;
import org.springframework.test.context.junit.jupiter.SpringExtension;
import org.springframework.test.web.servlet.MockMvc;
import org.springframework.test.web.servlet.setup.MockMvcBuilders;
import org.springframework.web.context.WebApplicationContext;
import java.util.List;
import static org.assertj.core.api.Assertions.assertThat;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post;
import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put;
import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
@ExtendWith(SpringExtension.class) //JUnit5 버전
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT) //컨트롤러,서비스,레포지토리사용할때
public class PostsApiControllerTest {
@LocalServerPort
private int port;
@Autowired
private PostsRepository postsRepository;
/*
--- 아래 context, mvc, setup() 해줘야 mvc를 @SpringBootTest로 사용할 수 있음(컨트롤러,서비스,레포지토리 테스트하려면)
--- 웹API(컨트롤러)만 테스트 하려면
@WebMvcTest(controllers = HelloController.class,
excludeFilters = {
@ComponentScan.Filter(type = FilterType.ASSIGNABLE_TYPE, classes = SecurityConfig.class)
}) 랑
@Autowired
private MockMvc mvc; 이거써서 테스트 가능
*/
@Autowired
private WebApplicationContext context;
private MockMvc mvc;
@BeforeEach
public void setup() {
mvc = MockMvcBuilders.webAppContextSetup(context).build();
}
@AfterEach
public void tearDown() throws Exception {
postsRepository.deleteAll();
}
@Test
@WithMockUser(roles = "USER")
public void Posts_등록된다() throws Exception {
//given
String title = "title";
String content = "content";
PostsSaveRequestDto requestsDto = PostsSaveRequestDto.builder()
.title(title)
.content(content)
.author("author")
.build();
String url = "http://localhost:" + port + "/api/v1/posts";
//when
mvc.perform(post(url)
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestsDto)))
.andExpect(status().isOk());
//then
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(title);;
assertThat(all.get(0).getContent()).isEqualTo(content);
}
@Test
@WithMockUser(roles = "USER")
public void Posts_수정된다() throws Exception {
//given
Posts savedPosts = postsRepository.save(Posts.builder().title("title").content("content").author("author").build());
Long updateId = savedPosts.getId();
String expectedTitle = "title2";
String expectedContent = "content2";
PostsUpdateRequestDto requestDto = PostsUpdateRequestDto.builder().title(expectedTitle).content(expectedContent).build();
String url = "http://localhost:" + port + "/api/v1/posts/" + updateId;
//when
mvc.perform(put(url)
.contentType(MediaType.APPLICATION_JSON)
.content(new ObjectMapper().writeValueAsString(requestDto)))
.andExpect(status().isOk());
//then
List<Posts> all = postsRepository.findAll();
assertThat(all.get(0).getTitle()).isEqualTo(expectedTitle);
assertThat(all.get(0).getContent()).isEqualTo(expectedContent);
}
}
참고링크:
https://velog.io/@gale4739/Spring-Boot-Controller-test-with-JUnit5
'springboot' 카테고리의 다른 글
[springboot] 구글 로그인 api 연동 (0) | 2024.02.18 |
---|---|
[springboot] 스프링에서 Bean 주입 시 @Autowired 사용을 권장하지 않는 이유 (1) | 2024.02.15 |
[springboot] JUnit 테스트에서 @Slf4j 사용하기 (0) | 2024.02.14 |
[토이프로젝트] h2-console mv.db 오류 해결 (0) | 2024.02.11 |
[springboot] jpa 엔티티 3점대 jakarta 패키지 주의사항 (0) | 2024.02.11 |