리액트 기초 공부해보기 #17 Springboot Junit 테스트2

KHS·2022년 1월 3일
0

지난 시간에 이어서 컨트롤러 테스트를 해보자

주소를 입력하여 테스트하기 위해 MockMvc를 DI해놓자 이걸 DI할 수 있는 이유는

이 친구 덕분이라는걸 잊지 말기!

다음 save_테스트라는 함수를 하나 만들고 이 함수는 테스트용이라는 뜻의 @Test어노를 붙여준다 그리고 @Slf4j를 이용하여 로그를 찍어보자! 이 파일에서 컨트롤+f11하면 바로 Junit이 실행 된다.

이렇게 실행을 했는데 ApplicationContext를 로드 할 수 없다고 에러가 났다. 그리고 BookService가 메모리에 등록이 되어 있는지 확인해 보라는 메세지도 있다. 이게 무슨 말이냐면 mockMvc는 필터랑 컨트롤어드바이스같은걸 띄워 준다. 그럼 띄울때 우리가 만든 BookController를 메모리에 띄우러 갈텐데 이걸 띄우러 갔더니 private final BookService bookService;이게 있는데, Service가 메모리에 안 떠있으니 이걸 @Autowired하지 못하는 것이다.

그럼 다시 ControllerUniTest로 돌아와서

@Mock
private BookService bookService;

이런식으로 @Mock을 저 서비스 위에 붙이면 될까? 앞서 말했던것 처럼 @WebMvcTest는 컨트롤러,필터, 컨트롤어드바이스 등을 메모리에 띄우는데 IoC컨테이너에서 컨트롤러를 띄울때 이 컨트롤러 안에 있는 private final BookService bookService요걸 띄울때도 똑같이 IoC컨테이너에서 찾는다. 그렇기에 @Mock로 띄운다고 되는 것이 아니다.

이렇게 @MockBean으로 바꿔주면 가짜 Service가 IoC 환경에 bean으로 등록이 된다.

다음으로 이렇게 book 객체를 넣어 데이터를 save하고 돌려받은 book을 sysout으로 찍어 보았는데. null이 나온다. 이 bookService가 가짜여서 그렇게 된 거고 실제 bookService면 null이 아니게 될거다.
이제 제대로 테스트를 해볼건데 BDDMockito패턴이라는 게 있다. 먼저 given (테스트를 하기 위한 준비)

먼저 new ObjectMapper().writeValueAsString(bookService); 이걸 통해 자바 객체를 Json데이터로 바꿔준다. (Json데이터 파싱 함수)

이런식으로 자바 객체를 Json데이터로 바꿀 수 있다.
반대로는 new ObjectMapper().readValue(null, null)이런식으로 쓰면 Json데이터를 자바 객체에 담을 수 있다.
이렇게 하는건 save데이터를 받을 때 Json데이터를 save의 매개변수에 넣을거기때문이다. 이러한 과정이 given이다.
다음은 이 bookService는 가짜인데 이 컨트롤러에서 /book이걸 입력할건데 그럼 bookService.저장하기가 실행되면서 이건 가짜객체라 null이 뜰 것이다.
그래서 stub이라는걸 만든다. stub은 가정법이라는건데 미리 행동을 지정을 하는 것이다.

이런식으로 book 객체를 Json데이터로 파싱하여 컨트롤러에 save함수에 매개변수로 넣을건데 어차피 이건 가짜객체라 리턴값도 null이고 우리는 이 컨트롤러라는 단위가 실행이 잘 되는지 확인을 위한거기 때문에 when다음에 어떤 행동을 지정할 수 있다.

밑줄 친 코드를 추가함으로써 내가 나올 결과를 지정을 해버리면, 실제로 이 아래 사진의 저장하기 함수가 실행이 되고

그 결과가 new Book(1L,"스프링따라하기","kim")로 리턴이 된다.

given의 다음 단계는 when이라는 것인데 이건 테스트를 실행하는 단계이다.

mockMvc의 perform이라는 함수를 이용하여 우리가 웹에서 요청하는 방식이랑 똑같은 환경을 만들어 준다. MediaType.APPLICATION_JSON_UTF8 이건 "application/json" 이 뜻이다. accept는 응답을 기대하는 마임타입.

그럼 이제 다시 컨트롤러로 돌아와서 저 save함수가 실행 될 때 bookService.저장하기가 실행되고 근데 이건 가짜객체라 실행해봤자 제대로 안될거고 이거에 대한 리턴 결과값이

요 밑줄친 부분이 될 것이다라는것.

이 코드의 리턴값을 ResultActions라는 타입으로 받을 수 있는다. 그리고 그럼 이거에 대한 기대값이 있는데 이걸 then이라고 부른다. 즉 검증하는 것이다. 여기서 통과해야 초록색이 뜨고 빨간색이면 통과하지 못한것.

다음 내가 검증할 값들을 저 resultAction에 넣는다.
제일 처음건 상태값을 201로 기대한다는것 그리고 jsonPath로 안에 값을 검증한다. 이 $는 전체 결과이고 거기에 .변수명이 나온다. 그리고 value에 해당 키에 대한 값을 넣는데 이건 title이 "스프링따라하기" 이게 맞는건지 검증 하는것
여기까진 기대하는것이고 마지막 행동으로 andDo를 사용하여 MockMvcResultHandlers.print()이렇게 입력하면 결과를 콘솔에 보여준다.
jsonpath에 대해 잠깐 알아보자면

이렇게 $를 입력하고 go를 누르면 전체가 보이고

store를 누르면 store안에 book이 보여진다. 그리고 또 .으로 연결하여 book을 누르면

book에 값들이 출력이 된다. 특정 번지수만 찾고 싶으면 저기에 $.store.book[0] 이런식으로 입력하고 특정 번지수부터 다 보고 싶으면 $.store.book[1:] 이런식으로 하면 된다 이건 1번지부터 전부 다 보여달라는것 $.store.book[*] 이렇게 하면 다 보고싶다 라는 뜻
그럼 여기서 더 자세하게 book 안에 author만 찾으려면 $.store.book[0].author 이런식으로 접근하면 된다.

그리고 실행을 하면 테스트에 성공하였다.
콘솔창을 보면 내가 요청한 데이터들과 응답 받은 데이터들을 확인 할 수 있다.
그럼 이제 통합테스트도 해볼건데 여기서 했던거 그대로 들고 간다.
여기선 실제 서비스가 실행 될 것이기때문에
when(bookService.저장하기(book)).thenReturn(new Book(1L,"스프링따라하기","kim")); 이 stub은 필요가 없어진다. 또한

@MockBean
private BookService bookService;

이렇게 가짜로 서비스를 등록할 필요도 없어진다. 그리고 여기선 실제로 실행이 되고 Repository 불러서 DB에 저장까지 되지만 @Transactional을 걸어놨기때문에 바로 롤백이 될 것이다.
차이점은 계속 말했듯이 메모리에 다 띄우기때문에 무겁다.

sql이 실행이 되었는지 확인하기 위해 yml에 show-sql: true라고 입력을 하면 테스트시 콘솔에 sql실행 되는 것도 확인할 수 있다.

이 게시물은 여기까지

이 글은 유튜브 메타코딩 채널의 영상을 보며 공부한 내용을 기록한 게시글입니다.

profile
천천히 개발 공부하기

0개의 댓글