controller
package com.cos.demo.web; import org.springframework.http.HttpStatus; import org.springframework.http.ResponseEntity; import org.springframework.web.bind.annotation.DeleteMapping; import org.springframework.web.bind.annotation.GetMapping; import org.springframework.web.bind.annotation.PathVariable; import org.springframework.web.bind.annotation.PostMapping; import org.springframework.web.bind.annotation.PutMapping; import org.springframework.web.bind.annotation.RequestBody; import org.springframework.web.bind.annotation.RestController; import com.cos.demo.domain.Book; import com.cos.demo.service.BookService; import lombok.RequiredArgsConstructor; @RequiredArgsConstructor @RestController public class BookController { private final BookService bookService; @PostMapping("/book") public ResponseEntity<?> save(@RequestBody Book book){ return new ResponseEntity<>(bookService.saveBook(book), HttpStatus.CREATED); } @GetMapping("/book") public ResponseEntity<?> findAll(){ return new ResponseEntity<>(bookService.getAllBook(), HttpStatus.OK); } @GetMapping("/book/{id}") public ResponseEntity<?> findById(@PathVariable Long id){ return new ResponseEntity<>(bookService.getBook(id), HttpStatus.OK); } @PutMapping("/book/{id}") public ResponseEntity<?> update(@PathVariable Long id, @RequestBody Book book){ return new ResponseEntity<>(bookService.getBook(id), HttpStatus.OK); } @DeleteMapping("/book/{id}") public ResponseEntity<?> deleteById(@PathVariable Long id){ return new ResponseEntity<>(bookService.deletBook(id), HttpStatus.OK); } }
1. 통합테스트 - BookControllerItegreTest
package com.cos.demo.web; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; 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.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.ArrayList; import java.util.List; import javax.persistence.EntityManager; 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.boot.test.context.SpringBootTest.WebEnvironment; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import org.springframework.transaction.annotation.Transactional; import com.cos.demo.domain.Book; import com.cos.demo.domain.BookRepository; import com.cos.demo.service.BookService; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; /** * 통합테스트 (모든 Bean 들을 똑같이 IOC 에 올리고 테스트하는 것) * WebEnvironment.MOCK=실제 톰켓을 올리는것이 아니라, 다른 톰켓으로 테스트 * WebEnvironment.RANDOM_PORT = 실제 톰켓으로 테스트 * * @AutoConfigureMockMvc MockMvc 를 IOC 에 등록해줌. * @Transactional 은 각각의 테스트함수가 종료될 때만다 트랜잭션을 rollback 해주는 어노테이션 */ @Slf4j @Transactional @AutoConfigureMockMvc @SpringBootTest(webEnvironment = WebEnvironment.MOCK) public class BookControllerItegreTest { @Autowired private MockMvc mockMvc; @Autowired private BookRepository bookRepository; @Autowired private EntityManager entityManager; // @BeforeEach // public void init(){ // List<Book> books =new ArrayList<Book>(); // books.add(new Book(null,"스프링부트 따라하기","코스")); // books.add(new Book(null,"리엑트 따라하기","코스")); // books.add(new Book(null,"JUnit 따라하기","코스")); // bookRepository.saveAll(books); // entityManager.createNativeQuery("ALTER TABLE book ALTER COLUMN id RESTART WITH 1").executeUpdate(); // //entityManager.createNativeQuery("ALTER TABLE book AUTO_INCREMENT=1").executeUpdate(); // } // // @AfterEach // public void end(){ // bookRepository.deleteAll(); // } @Test public void save_테스트() throws Exception { log.info("save_테스트() 시작 =========================="); //given (테스트를 하기 위한 준비) Book book=new Book(null, "스프링 따라하기", "코스"); String content=new ObjectMapper().writeValueAsString(book); log.info(content); //when(테스트 실행) ResultActions resultActions =mockMvc.perform(post("/book").contentType( MediaType.APPLICATION_JSON).content(content).accept(MediaType.APPLICATION_JSON)); //then(검증) //https://jsonpath.com/ resultActions .andExpect(status().isCreated()) .andExpect(jsonPath("$.title").value("스프링 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void findAll_테스트() throws Exception{ //given List<Book> books=new ArrayList<>(); books.add(new Book(1L,"스프링부트 따라하기", "코스")); books.add(new Book(2L,"리엑트 따라하기", "코스")); bookRepository.saveAll(books); //when ResultActions resultActions=mockMvc.perform(get("/book") .accept(MediaType.APPLICATION_JSON)); //공식문서 : https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing //https://jsonpath.com/ //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$", Matchers.hasSize(2))) .andExpect(jsonPath("$.[0].title").value("스프링부트 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void findById_테스트() throws Exception{ List<Book> books =new ArrayList<Book>(); books.add(new Book(null,"스프링부트 따라하기","코스")); books.add(new Book(null,"리엑트 따라하기","코스")); books.add(new Book(null,"JUnit 따라하기","코스")); bookRepository.saveAll(books); Long id=1L; ResultActions resultActions=mockMvc.perform(get("/book/{id}", id) .accept(MediaType.APPLICATION_JSON)); //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("스프링부트 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void update_테스트() throws Exception{ Long id=1L; List<Book> books =new ArrayList<Book>(); books.add(new Book(null,"스프링부트 따라하기","코스")); books.add(new Book(null,"리엑트 따라하기","코스")); books.add(new Book(null,"JUnit 따라하기","코스")); bookRepository.saveAll(books); Book book=new Book(id, "C++ 따라하기","코스"); String content=new ObjectMapper().writeValueAsString(book); //영속성 객체 가져오기 Book entitiy=bookRepository.findById(id).orElseThrow(()->new IllegalArgumentException("ID 를 찾을 수 없습니다.")); entitiy.setTitle(book.getTitle()); //when ResultActions resultActions=mockMvc.perform( put("/book/{id}", id) .contentType(MediaType.APPLICATION_JSON) .content(content) .accept(MediaType.APPLICATION_JSON)); //공식문서 : https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing //https://jsonpath.com/ //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("C++ 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void delete_테스트() throws Exception{ Long id=1L; Book book=new Book(id, "C++ 따라하기","코스"); bookRepository.save(book); //삭제처리시 예상값 //when(bookService.deletBook(id)).thenReturn("ok"); //when ResultActions resultActions=mockMvc.perform(delete("/book/{id}", id) .accept(MediaType.TEXT_PLAIN)); //then resultActions .andExpect(status().isOk()) .andDo(MockMvcResultHandlers.print()); MvcResult requestResult=resultActions.andReturn(); String result=requestResult.getResponse().getContentAsString(); log.info("1.resultActions ==>{}", resultActions); log.info("2.result ==>{}", result); assertEquals("ok", result); } }
2. 단위 테스트 -BookControllerUnitTest
package com.cos.demo.web; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.mockito.Mockito.when; import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.delete; 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.put; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; import java.util.ArrayList; import java.util.List; import org.hamcrest.Matchers; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.web.servlet.WebMvcTest; import org.springframework.boot.test.mock.mockito.MockBean; import org.springframework.http.MediaType; import org.springframework.test.web.servlet.MockMvc; import org.springframework.test.web.servlet.MvcResult; import org.springframework.test.web.servlet.ResultActions; import org.springframework.test.web.servlet.result.MockMvcResultHandlers; import com.cos.demo.domain.Book; import com.cos.demo.service.BookService; import com.fasterxml.jackson.databind.ObjectMapper; import lombok.extern.slf4j.Slf4j; //단위테스트(Controller 관련 로직만 띄우기) Filter, ControllerAdvice @Slf4j //@Transactional @WebMvcTest public class BookControllerUnitTest { @Autowired private MockMvc mockMvc; @MockBean //IoC 환경에 bean 등록됨. private BookService bookService; //BDDMockito 패턴 given, when, then @Test public void save_테스트() throws Exception { log.info("save_테스트() 시작 =========================="); //given (테스트를 하기 위한 준비) Book book=new Book(null, "스프링 따라하기", "코스"); String content=new ObjectMapper().writeValueAsString(book); log.info(content); //결과값을 미리 설정 when(bookService.saveBook(book)).thenReturn(new Book(1L,"스프링 따라하기", "코스")); //when(테스트 실행) ResultActions resultActions =mockMvc.perform(post("/book").contentType( MediaType.APPLICATION_JSON).content(content).accept(MediaType.APPLICATION_JSON)); //then(검증) //https://jsonpath.com/ resultActions .andExpect(status().isCreated()) .andExpect(jsonPath("$.title").value("스프링 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void findAll_테스트() throws Exception{ //given List<Book> books=new ArrayList<>(); books.add(new Book(1L,"스프링부트 따라하기", "코스")); books.add(new Book(2L,"리엑트 따라하기", "코스")); //결과값을 미리 설정 when(bookService.getAllBook()).thenReturn(books); //when ResultActions resultActions=mockMvc.perform(get("/book") .accept(MediaType.APPLICATION_JSON)); //공식문서 : https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing //https://jsonpath.com/ //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$", Matchers.hasSize(2))) .andExpect(jsonPath("$.[0].title").value("스프링부트 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void findById_테스트() throws Exception{ Long id=1L; when(bookService.getBook(id)).thenReturn(new Book(1L, "자바 공부하기", "쌀")); ResultActions resultActions=mockMvc.perform(get("/book/{id}", id) .accept(MediaType.APPLICATION_JSON)); //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("자바 공부하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void update_테스트() throws Exception{ Long id=1L; Book book=new Book(id, "C++ 따라하기","코스"); String content=new ObjectMapper().writeValueAsString(book); //결과값을 미리 설정 when(bookService.updateBook(id,book)).thenReturn(new Book(id,"C++ 따라하기","코스")); //when ResultActions resultActions=mockMvc.perform( put("/book/{id}", id) .contentType(MediaType.APPLICATION_JSON) .content(content) .accept(MediaType.APPLICATION_JSON)); //공식문서 : https://docs.spring.io/spring-boot/docs/current/reference/html/features.html#features.testing //https://jsonpath.com/ //then resultActions .andExpect(status().isOk()) .andExpect(jsonPath("$.title").value("C++ 따라하기")) .andDo(MockMvcResultHandlers.print()); } @Test public void delete_테스트() throws Exception{ Long id=1L; Book book=new Book(id, "C++ 따라하기","코스"); bookService.saveBook(book); //삭제처리시 예상값 when(bookService.deletBook(id)).thenReturn("ok"); //when ResultActions resultActions=mockMvc.perform(delete("/book/{id}", id) .accept(MediaType.TEXT_PLAIN)); //then resultActions .andExpect(status().isOk()) .andDo(MockMvcResultHandlers.print()); MvcResult requestResult=resultActions.andReturn(); String result=requestResult.getResponse().getContentAsString(); log.info("1.resultActions ==>{}", resultActions); log.info("2.result ==>{}", result); assertEquals("ok", result); } }
3. 서비스 - BookServiceUnitTest
package com.cos.demo.service; import org.junit.jupiter.api.Test; import org.junit.jupiter.api.extension.ExtendWith; import org.mockito.InjectMocks; import org.mockito.Mock; import org.mockito.junit.jupiter.MockitoExtension; import com.cos.demo.domain.BookRepository; //단위테스트(Controller, Filter, ControllerAdvice) //BookRepository => 가짜 객체로 만들 수 있음. @ExtendWith(MockitoExtension.class) public class BookServiceUnitTest { @InjectMocks //BookService 객체가 만들어 질때 BookServiceUnitTest 파일에 @Mock 로 등록된 모든 애들을 주입받는다. private BookService bookService; @Mock private BookRepository bookRepository; @Test public void save_테스트(){ } }
4. Repository - BookRepositoryUnitTest
package com.cos.demo.domain; import static org.junit.jupiter.api.Assertions.assertEquals; import org.junit.jupiter.api.Test; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase; import org.springframework.boot.test.autoconfigure.jdbc.AutoConfigureTestDatabase.Replace; import org.springframework.boot.test.autoconfigure.orm.jpa.DataJpaTest; import org.springframework.transaction.annotation.Transactional; //단위테스트(Controller, Filter, ControllerAdvice @Transactional @AutoConfigureTestDatabase(replace = Replace.ANY) //Replace.ANY 가짜 디비로 테스트, Replace.None 실제 DB 로 테스트 @DataJpaTest() //Repository 들을 다 IOC 등록해둠. public class BookRepositoryUnitTest { @Autowired private BookRepository bookRepository; @Test public void save_테스트(){ Book book=new Book(null,"책제목1","책저자1"); Book bookEntity=bookRepository.save(book); assertEquals("책제목1", bookEntity.getTitle()); } }
1.
2.
3.
4.
댓글 ( 0)
댓글 남기기