본 시리즈는 메타 코딩님의 Junit 강의를 학습한 내용을 바탕으로 정리하였습니다.
CRUD의 마지막... Update가 남아있다. 사실 웹 개발을 하면서 수 많은 CRUD를 해보았고, 많이 익숙한 개념이다. 그렇지만 익숙하다고 해서 그것이 중요하지 않은 것은 아니다. 가장 기본이자 가장 핵심이 되는 내용이 REST API이기 때문에 이를 몇번이고 반복해서 학습하며 기반을 잘 닦아놓아야 이를 토대로 여러 가지 다른 재밌는 일들을 할 수 있다고 생각한다.
(각설하고)
BookRepository.java
@DataJpaTest
public class BookRepositoryTest {
@Autowired
private BookRepository bookRepository;
@BeforeEach // 각 테스트 시작전에 한번씩 실행
public void 데이터준비() {
String title = "junit5";
String author = "메타코딩";
Book book = Book.builder()
.title(title)
.author(author)
.build();
bookRepository.save(book);
}
// 1. 책 등록
// 2. 책 목록보기
// 3. 책 한건 보기
// 4. 책 삭제
// ...(생략)
// 5. 책 수정
@Sql("classpath:db/tableIni.sql")
@Test
public void 책수정_test() {
// given
Long id = 1L;
String title = "Junit"; // 1.
String author = "겟인데어"; // 1.
Book book = new Book(id, title, author);
// when
Book bookPS = bookRepository.save(book);
// then
assertEquals(id, bookPS.getId());
assertEquals(title, bookPS.getTitle());
assertEquals(author, bookPS.getAuthor());
}
Junit
, 겟인데어
) 를 삽입한다.그런데 신기한 점이 있다. 실제로 DB에 반영할 업데이트에 관한 쿼리를 하나도 만들지 않았는데 어떻게 title
과 author
의 내용만 가지고 업데이트가 반영될까?
다음에 해답이 있다.
💡 더티 체킹이란?
데이터의 값을 변경하면 트랜잭션이 끝나는 시점에 해당 테이블에 변경분을 반영하는 것을 말한다. 즉, Entity 객체의 값만 변경하면 별도로 Update 쿼리를 날릴 필요가 없는 것이다.
이 개념으로 인해 책 수정 테스트를 이대로 완료해도 괜찮지만 그래도 직접 확인을 하는 것이 좋기에 눈으로 확인할 수 있게끔 테스트를 변경해보자.
BookRepositoryTest.java
// 4. 책 수정
@Sql("classpath:db/tableIni.sql")
@Test
public void 책수정_test() {
// given
Long id = 1L;
String title = "Junit";
String author = "겟인데어";
Book book = new Book(id, title, author);
// when
bookRepository.findAll().stream()
.forEach(b) -> {
System.out.println(b.getId());
System.out.println(b.getTitle());
System.out.println(b.getAuthor());
System.out.println("1. ==================");
});
Book bookPS = bookRepository.save(book);
bookRepository.findAll().stream()
.forEach((b) -> {
System.out.println(b.getId());
System.out.println(b.getTitle());
System.out.println(b.getAuthor());
System.out.println("2. ==================");
});
System.out.println(bookPS.getId());
System.out.println(bookPS.getTitle());
System.out.println(bookPS.getAuthor());
System.out.println("3. ==================");
}
위 테스트로 예상할 수 있는 출력 로그는 다음과 같고, 그 아래는 이에 대한 해석이다.
1. ==================
null
2. ==================
1
Junit
겟인데어
3. ==================
1
Junit
겟인데어
: 책 수정 테스트 시작 전에 실행되는 @BeforeEach
데이터 준비 메소드의 내용이 @Sql("classpath:db/tableIni.sql")
문에 의해 모두 삭제되어 null 값이 될 것이다.
: Book bookPS = bookRepository.save(book);
에 의해 새롭게 save
가 된 상태이다. 값이 변경된 상태이기 때문에 업데이트가 일어났을 것이고, 따라서 Junit
, 겟인데어
가 출력되었을 것이다.
: 업데이트가 반영된 이후의 데이터 내용을 출력했을 것이므로 2의 내용이 그대로 출력되었을 것이다.
실제 전체 테스트를 돌려보면...
뭔가 이상하다. 분명히 테이블을 새로 만드는 쿼리를 날렸는데 @BeforeEach
의 내용이 남아있다.. 왜일까? (아래의 의문점❓ 참조)
이 외에는 우리가 기대한 값이 잘 출력되었다.
위에서 본 것처럼 책 수정 테스트에 한 가지 의문점이 발생한다. 전에 언급된 트랜잭션의 실행 흐름은 다음과 같다.
이렇게 하나의 세트처럼 움직이게 되고 책 수정 테스트를 시작할 때는 @Sql("classpath:db/tableIni.sql")
어노테이션이 붙어있다.
즉,
@Sql("classpath:db/tableIni.sql")
쿼리를 통해 테이블을 모두 날리는 작업이 분명히 진행되게 된다. 그런데 왜 테스트 진행시 @BeforeEach
에서 삽입된 값이 삭제되지 않고 위에서 본 것 처럼 이렇게
1. ==================
1
Junit5
메타코딩
남아있을까?
이에 대한 내용은 다음 포스팅에서...