이번에 과제를 진행하면서 테스트 코드를 작성하던 중 고민을 해볼 지점이 생겼다.
현재 내 테스트 코드는 DB에 값을 insert한다거나 update, delete 하는 등 DB에 접근하는 행위들이 있다.
테스트마다의 독립성을 보장하기 위해서, 나는 각 테스트마다 진행된 것들이 다른 테스트에 영향을 끼치지 않기 위해 끝나면 롤백해주고 싶다.
현재 코드에는 그런 기능을 하는 것이 두 개가 동시에 들어가고 있다.
@Transactional , @AfterEach의 db.clear()
여기서 내가 조금 걱정이 되었던 부분은, 각 테스트가 실행될 때마다 db를 clear를 통해 다 지우는 것이 과연 합리적일까? 라는 생각이 들었다. 그냥 내가 수정한 부분들만 rollBack을 해주면 되는 것 아닐까? 라는 생각이 들었다.
해당 관점에서는 @Transactional을 쓰는 것이 난 조금 더 유효하다고 생각했다.
그렇다면 실제 Production과 Test에서의 @Transactional의 차이는 무엇이 있을까?
production 에서는 하나의 작업이나 여러의 작업을 하나의 작업 단위로 묶어서 Commit이나 Rollback 처리가 필요할 때 사용한다.
문제가 생기면 해당 작업들을 Rollback해준다.
test에서는 @Transactional을 붙이면, DB에 저장된 결과를 commit하지 않고 롤백해준다.
그렇기에 내가 원하는 결과를 얻게 된다.
test에서의 @Transactional, 편리해보인다.
하지만 test 코드의 @Transactional을 알아보던 중 주의할 점들이 보여 공유하게 되었다.
https://www.inflearn.com/questions/792383
하지만 @Transactional 테스트는 테스트 수행 중에 단 한 개의 트랜잭션 경계만 사용이 되고, 그 경계를 테스트 메소드로 확장을 해도 문제가 없는 상황에서만 유효합니다.
* JPA의 detached 상태 오브젝트의 변경이 자동감지 되지 않는 코드가 @Transactional 테스트에서는 정상 동작하게 보이는 현상
* JPA에서는 save한 오브젝트가 영속 컨텍스트에만 존재하고 db로 flush되지 않은 상태로 rollback되기 때문에 명시적으로 flush하지 않으면 실제 db 매핑에 문제가 있어도 검증하지 못한다는 문제
@Transactional 대신 tearDown 등에서 db를 클리어 하는 작업은 불가능한 건 아니지만 별로 추천하고 싶지 않습니다. 테스트 이전 상태가 모든 데이터가 다 비어있는 것으로 하기도 하지만, 어느 정도 초기 데이터 상태를 db에 넣고 하는 경우도 많은데, 데이터를 클리어하는 작업에서 이를 정확하게 원복한다는게 롤백 방식을 쓰지 않으면 매우 귀찮고 실수하기 쉽습니다.
김영한 님한테 @Transactional 롤백 테스트 쓰는 대신에 커밋시키고 tearDown에서 복원하는 방법에 대해서 물어봤습니다.
답변은
"그러면 실용성이 너무 떨어지잖아요. 몇가지 조심하면 되는데 그것 때문에 오만가지 불편함을 감수하면서 초가삼간 다 태울 수 없으니..."
'스프링 정리' 카테고리의 다른 글
Path Variable vs Query Parameter (0) | 2023.11.19 |
---|---|
왜 생성자 주입이 @Autowired(필드 주입)보다 좋을까? (0) | 2023.11.07 |
Spring Batch - @PersistJobDataAfterExecution (0) | 2023.04.04 |
Spring Security & JWT(Json Web Token) 활용 예제 (0) | 2023.03.28 |
Spring Batch & Quartz 활용해보기 (0) | 2023.03.24 |