-
[Spring JPA] 왜 테스트코드와 실제 어플리케이션코드가 실행이 다르게 될까?Back End/Spring Data JPA 2021. 12. 24. 17:39
실제 API 호출코드는 아무 문제 없이 잘돌아가는데
똑같이 실행될거라 여겨진 테스트코드가
오류를 내뱉거나 쿼리가 예상과는 다르게 작동하는 것을
경험하신분들이라면 잘 찾아 오셨다 🥳🥳🥳
원인은 JUnit 과 Spring Test 에 대한 이해도 부족일 것이다.
모든 테스트 케이스를 다룰 수 없으니 하나만 예시를 들어보겠다.
따라서 해당 현상을 경험하신분이라면 JUnit + Spring Test 에 대해 공부하시는게 좋다.
( 테스트 환경을 실제환경과 동일한 구성을 하기 위해서는 노력이 많이 필요하다. )
테스트환경 구축방법을 제대로 알지 못한채
테스트 코드를 설계하는 것은
지옥으로 가는 지름길이라는 것을 알아두자.
(JPA 도 그렇다)
ㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋㅋ
일단 여기까지 오신분들은 영속성이 무엇이고 @Transactional 이 무엇인지는 다들 알고 계실꺼라 확신한다.
필자는 그 개념에 따라 테스트코드를 작성하였는데, 예상과 다르게 돌아가서 맞왜틀(맞는데 왜 틀리지..)의 늪에서 허우적이고 있었다.
[대부분의 원인]
>>> 테스트코드의 어노테이션을 정확히 몰라서 발생한다.
@DataJpaTest 어노테이션을 보면 아래와 같다.
즉, @DataJpaTest 는 @Transactional 을 포함하고 있고
이는 각 테스트(메서드)마다 @Transcational 을 달아준 것과 동일한 기능을 한다.
* 추가정보) @DataJpaTest 는 @Configuration 을 빈으로 불러오지 않는다. (Auditing 이 안되는 경우 해당링크 참조)
그리하여 예를 들자면, API 컨트롤러에서 @Transactional 없이 코드를 작성하고,
동일하게 테스트코드를 작성하면 다른결과를 통보받는 것이다.
(운이 좋으면 SQL 호출 횟수만 다를텐데, 운이 나쁘면 Lazy initialization Exception 을 마주할때도 있을 것이다.)
아래는 SQL 호출 횟수가 달라지는 예시이다.
[SQL 호출횟수가 달라지는 현상]
* Post 객체는 Blog 와 @ManyToOne 연관관계를 맺고 있고, FetchType.EAGER, CascadeType.ALL 이라 가정하겠다.
/* ------------------ Application Code Below ----------------- */ @Controller public class MyController{ @Autowired BlogRepository blogRepository; @Getmapping("/blogs") @ResponseBody public List<Blog> blogs(){ return blogRepository.findAll(); ////// Actual Query /////// /* 1. blog 를 select 하는 쿼리문 발생 2. blog 가 가지고 있는 post 를 select 하는 쿼리문 발생 */ } } /* ------------------ Application Code Above ----------------- */ /* ------------------ Test Code Below ----------------- */ @DataJpaTest public class PostRepositoryTest(){ @Autowired BlogRepository blogRepository; @Autowired PostRepository postRepository; @Test void ReadTest(){ Blog blog1 = new Blog("공부하는 개발자 Ping9"); Blog blog2 = new Blog("누워서 일하는 개발자 Hing9"); Post post1 = new Post("SQL Injection에 관하여", blog1); Post post2 = new Post("Log4j 의 보안 이슈", blog2); // Cascade.ALL 로 연결되어있다고 가정 postRepository.save(post1); postRepository.save(post2); ////// Expected Query ////// /* 1. select blog + 2. select post */ blogRepository.findAll().forEach(System.out::println); /////// Actual Query /////// /* 1. select blog */ // 이유 : 같은 트랜잭션임, select 가 나가는 이유는 blog1,2 말고 더 있나 싶어서 날리는 것 일뿐. } }
[Reference]
1. Spring Boot Test (NHN Colud)
728x90'Back End > Spring Data JPA' 카테고리의 다른 글
[Spring JPA] JPA에서 Lazy loading 은 도대체 어떻게 이루어지는 걸까? (0) 2021.12.24 [Spring JPA] Spring Test 에서 Auditing 이 안될때 (@DataJpaTest) (0) 2021.12.24 [Spring JPA] JPA의 사실과 오해 (feat. NHN Cloud) (0) 2021.12.23 [Spring JPA] Setter를 사용하지 않는다. (0) 2021.11.30 [Spring JPA] FetchType 이란? (EAGER, LAZY Fetch) (0) 2021.11.02