라이브러리 그래들
testImplementation 'org.junit.jupiter:junit-jupiter-api:5.8.1' testRuntimeOnly 'org.junit.jupiter:junit-jupiter-engine:5.8.1' testImplementation 'org.springframework.boot:spring-boot-starter-test' testImplementation 'org.springframework.security:spring-security-test'
컨트롤에서 샘플 데이터
HelloController
import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RestController; @RestController public class HelloController { @GetMapping("/hello") public String hello(){ return "hello"; } @GetMapping("/hello/dto") public HelloResponseDto helloDto(@RequestParam("name") String name, @RequestParam("amount") int ammount ){ return new HelloResponseDto(name, ammount); } }
HelloResponseDto
import lombok.AllArgsConstructor; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.RequiredArgsConstructor; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.RequestParam; import java.io.Serializable; @Getter @RequiredArgsConstructor public class HelloResponseDto implements Serializable { private final String name; private final int ammount; }
PostsDto
import com.jojoIdu.book.srpingboot.domain.entity.Posts; import lombok.*; import java.time.LocalDateTime; @Getter @NoArgsConstructor @ToString public class PostsDto { private Long id; private String title; private String content; private String author; private LocalDateTime modifiedDate; public PostsDto(Posts entity){ this.id=entity.getId(); this.title=entity.getTitle(); this.content=entity.getContent(); this.author=entity.getAuthor(); this.modifiedDate=entity.getModifiedDate(); } @Builder public PostsDto(String title, String content, String author){ this.title=title; this.content=content; this.author=author; } public Posts toEntity() { return Posts.builder() .title(title) .content(content) .author(author) .build(); } }
PostsApiController
import lombok.RequiredArgsConstructor; import lombok.extern.slf4j.Slf4j; import org.springframework.web.bind.annotation.*; @RequiredArgsConstructor @RestController @Slf4j public class PostsApiController { private final PostsService postsService; @PostMapping("/api/v1/posts") public Long save(@RequestBody PostsDto requestDto) throws Exception { return postsService.save(requestDto); } @PutMapping("/api/v1/posts/{id}") public Long update(@PathVariable Long id, @RequestBody PostsDto requestDto){ return postsService.update(id, requestDto); } @GetMapping("/api/v1/posts/{id}") public PostsDto findById(@PathVariable Long id){ return postsService.findById(id); } @DeleteMapping("/api/v1/posts/{id}") public Long delete(@PathVariable Long id){ postsService.delete(id); return id; } }
인텔리 제이에서 테스트 클래스 생성 방법
해당 클래스 또는 메소드에서 마우스 우클릭 -> Generate -> test 선택 -> 메소드 선택
2. 이클립스에서 테스트 클래스 생성 방법
[Eclipse] 자바 JUnit 사용 방법 & 단위 테스트 방법
출처: https://junghn.tistory.com/entry/Eclipse-자바-JUnit-사용-방법-단위-테스트-방법 [코딩 시그널]
①private.MockMvc mvc
웹 API 를 테스트할 때 사용.
스프링 MVC 테스트의 시작점
이 클래스를 통해 HTTP GET, POSt 등에 대한 API 테스트를 할 수 있음.
② mvc.perform(get("/hello"))
MockMvc 를 통해/hello 주소로 HTTP GET 요청을 한다.
체이닝이 지원되어 아래와 같이 여러 검증 기능을 이어서 선언할 수 있음
③ .andExpect(status().isOk())
.mvc.perform 의 결과를 검증.
HTTP Header의 Status 를 검증.
우리가 흔히 알고 있는 200, 404, 500 등의 상태를 검증한다.
여기선 OK 즉, 200인지 아닌지를 검증
④ .andExpect(content().string(hello))
.mvc perform 의 결과를 검증
.응답 본문의 내용을 검증
.Controller 에서 "hello" 를 리턴하기 때문에 이 값이 맞는 검증
Junit5 테스트 하기
간단한 테스트일 경우
@AutoConfigureMockMvc 를 통해 Spring Boot 에서 사용되는 여러 설정(@Service 등) 을 사용하도록 선언
그러나 다음은 공통 상속 클래스 만들어서 사용하는 처리 방법
1. AbstractControllerTest
공통 상속 클래스 만들기
import org.junit.jupiter.api.BeforeEach; import org.springframework.boot.test.context.SpringBootTest; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.setup.MockMvcBuilders; import org.springframework.web.filter.CharacterEncodingFilter; import java.nio.charset.StandardCharsets; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; @SpringBootTest public abstract class AbstractControllerTest { protected MockMvc mockMvc; abstract protected Object controller(); @BeforeEach private void setup() { mockMvc = MockMvcBuilders.standaloneSetup(controller()) .addFilter(new CharacterEncodingFilter(StandardCharsets.UTF_8.name(), true)) .alwaysDo(print()) .build(); } }
2. HelloControllerTest
import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import org.springframework.http.MediaType; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.*; import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print; import org.junit.jupiter.api.DisplayName; public class HelloControllerTest extends AbstractControllerTest{ @Autowired private HelloController helloController; @Override protected Object controller() { return helloController; } @Test @DisplayName("hello가_리턴 ---- 테스트") void hello가_리턴된다() throws Exception { String content = "hello"; this.mockMvc.perform( get("/hello") .contentType(MediaType.APPLICATION_JSON) .content(content) ) .andExpect(status().isOk()) .andExpect( content().string("hello")) .andDo(print()); } @Test @DisplayName("helloDto가_리턴된다") public void helloDto가_리턴된다() throws Exception{ String name="hello"; int amount =10000; ObjectMapper objectMapper=new ObjectMapper(); HelloResponseDto dto =new HelloResponseDto(name, amount); String expectedJson =objectMapper.writeValueAsString(dto); this.mockMvc.perform( get("/hello/dto") .param("name", name) .param("amount", String.valueOf(amount)) ) .andExpect(status().isOk()) .andExpect( content().string(expectedJson)); } }
PostsApiControllerTest
import com.fasterxml.jackson.databind.ObjectMapper; import com.jojoIdu.book.srpingboot.domain.entity.Posts; import com.jojoIdu.book.srpingboot.domain.repository.PostsRepository; import com.jojoIdu.book.srpingboot.web.dto.PostsDto; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.web.server.LocalServerPort; import org.springframework.http.MediaType; import org.springframework.security.test.context.support.WithMockUser; 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.junit.jupiter.api.Assertions.assertEquals; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.put; import static org.springframework.security.test.web.servlet.setup.SecurityMockMvcConfigurers.springSecurity; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.post; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; class PostsApiControllerTest extends AbstractControllerTest { @Autowired private PostsApiController postsApiController; @Autowired private WebApplicationContext context; private MockMvc mvc; @LocalServerPort private int port; @Autowired private PostsRepository postsRepository; //시큐리티 보안설정 @BeforeEach public void setup(){ mvc = MockMvcBuilders .webAppContextSetup(context) .apply(springSecurity()) .build(); } @Override protected Object controller() { return postsApiController; } /** * @WithMockUser(roles = "USER") 인증된 모의(가짜) 사용자를 만들어서 사용한다. roles 에 권한을 추가할 수 있다. 즉, 어노테이션으로 인해 ROLE_USER 권한을 가진 사용자가 API를 요청하는 것과 동일한 효과를 가지게 된다. */ @DisplayName("posts_등록된다()") @Test @WithMockUser(roles = "USER") public void posts_등록된다() throws Exception { String title="title- 테스트"; String content="홍길동"; PostsDto requestDto=PostsDto .builder() .title(title) .content(content) .build(); System.out.println(" 등록된다......."); String url ="http://localhost:"+port+"/api/v1/posts"; //when mvc.perform(post(url) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(new ObjectMapper().writeValueAsString(requestDto))) .andExpect(status().isOk()); //then List<Posts> all = postsRepository.findAll(); assertEquals(all.get(0).getTitle(),title ); assertEquals(all.get(0).getContent(),content); } @DisplayName("post_수정()") @Test @WithMockUser(roles = "USER") public void post_수정() 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"; PostsDto requestDto = PostsDto.builder() .title(expectedTitle) .content(expectedContent) .build(); String url = "http://localhost:" + port + "/api/v1/posts/" + updateId; //when mvc.perform(put(url) .contentType(MediaType.APPLICATION_JSON_UTF8) .content(new ObjectMapper().writeValueAsString(requestDto))) .andExpect(status().isOk()); //then List<Posts> all = postsRepository.findAll(); assertEquals(all.get(0).getTitle(), expectedTitle ); assertEquals(all.get(0).getContent(),expectedContent); } }
소스 : https://github.com/braverokmc79/AwsAndSpringBoot
참고 :
1 )[JUnit5] MockMvc로 Spring Boot 통합 테스트하기
2) Spring Boot JUnit 5 MockMvc Test
3) Spring Boot 에서 JUnit5 , MockMvc를 이용하여 테스트 진행하기
스프링 부트와 AWS로 혼자 구현하는 웹 서비스
이동욱 저
가장 빠르고 쉽게 웹 서비스의 모든 과정을 경험한다. 경험이 실력이 되는 순간!이 책은 제목 그대로 스프링 부트와 AWS로 웹 서비스를 구현한다. JPA와 JUnit 테스트, 그레이들, 머스테치, 스프링 시큐리티를 활용한 소셜 로그인 등으로 애플리케이션을 개발하고, 뒤이어 AWS 인프라의 기본 사용법과 AWS EC2와 RDS를 사용...
댓글 ( 4)
댓글 남기기