-
db 테스트에서의 트랜잭션스프링/스프링 기초DB 2023. 3. 25. 16:18
db를 테스트코드를 이용해서 테스트해 볼 것이다.
test에 있는 application.properties에
spring.profiles.active=test spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase spring.datasource.username=sa spring.datasource.password=
를 추가해줘서 데이터베이스에 연결할 수 있도록 해줬다.
class ItemRepositoryTest { @Autowired ItemRepository itemRepository; @AfterEach void afterEach() { //MemoryItemRepository 의 경우 제한적으로 사용 if (itemRepository instanceof MemoryItemRepository) { ((MemoryItemRepository) itemRepository).clearStore(); } }
@Test void save() { //given Item item = new Item("itemA", 10000, 10); //when Item savedItem = itemRepository.save(item); //then Item findItem = itemRepository.findById(item.getId()).get(); assertThat(findItem).isEqualTo(savedItem); }
item을 저장하는 테스트 코드이다
@Test void updateItem() { //given Item item = new Item("item1", 10000, 10); Item savedItem = itemRepository.save(item); Long itemId = savedItem.getId(); //when ItemUpdateDto updateParam = new ItemUpdateDto("item2", 20000, 30); itemRepository.update(itemId, updateParam); //then Item findItem = itemRepository.findById(itemId).get(); assertThat(findItem.getItemName()).isEqualTo(updateParam.getItemName()); assertThat(findItem.getPrice()).isEqualTo(updateParam.getPrice()); assertThat(findItem.getQuantity()).isEqualTo(updateParam.getQuantity()); }
item을 수정하는 테스트 코드이다.
@Test void findItems() { //given Item item1 = new Item("itemA-1", 10000, 10); Item item2 = new Item("itemA-2", 20000, 20); Item item3 = new Item("itemB-1", 30000, 30); itemRepository.save(item1); itemRepository.save(item2); itemRepository.save(item3); //둘 다 없음 검증 test(null, null, item1, item2, item3); test("", null, item1, item2, item3); //itemName 검증 test("itemA", null, item1, item2); test("temA", null, item1, item2); test("itemB", null, item3); //maxPrice 검증 test(null, 10000, item1); //둘 다 있음 검증 test("itemA", 10000, item1); } void test(String itemName, Integer maxPrice, Item... items) { List<Item> result = itemRepository.findAll(new ItemSearchCond(itemName, maxPrice)); assertThat(result).containsExactly(items); } }
findItems를 하는 테스트 코드이다.
위의 저장과 수정은 오류가 나지 않지만 findItems()를 실행하면 오류가 난다. 그 이유는 db에 계속해서 데이터가 누적되기 때문이다. save에서 ItemA가 db에 저장되었고, update에서 Item1이 db에 저장되었다. 그런데 test(null, null, item1, item2, item3);이라는 문장은 item1, item2, item3만 test에 있다는 것을 확인하기 때문에 오류가 발생한다.
테스트는 다른 테스트와 격리해서 진행해야하고, 반복해서 실행할 수 있어야한다.
일단 h2콘솔에서 jdbc:h2:tcp://localhost/~/test대신 jdbc:h2:tcp://localhost/~/testcase 경로로 다른 db를 만들고, 반복해서 실행할 수 있도록 롤백해줘야한다. 이럴 때 사용하는 것이 트랜잭션이다.
@Transactional 애노테이션
@Transactional @SpringBootTest class ItemRepositoryTest {
클래스 위에 @Transactional이라는 애노테이션을 추가해주면 된다.
일반적으로는 로직이 성공적으로 실행되면 커밋을 하고, 아니면 롤백을 해준다. 하지만 테스트 코드에서는 로직이 성공해도 롤백을 해주는 기능이 별도로 있다.
@Commit // @Rollback(false) @Test void save() { //given Item item = new Item("itemA", 10000, 10); //when Item savedItem = itemRepository.save(item); //then Item findItem = itemRepository.findById(item.getId()).get(); assertThat(findItem).isEqualTo(savedItem); }
만약에 트랜잭션을 사용하는데 별도로 커밋을 통해 확인하고 싶은 경우가 있을 수도 있다. 다른 기능은 직접 보지 않아도 상관없는데 상품을 저장하는 로직은 한 번 눈으로 확인하고 싶다는 생각이 된다면 해당 테스트 메서드 위에 @Commit이나 @Rollback(false) 애노테이션을 붙이면 된다.
테스트 케이스에도 트랜잭션 애노테이션이 있고, 리포지토리에도 트랜잭션 애노테이션이 있다고 할 지라도 같은 트랜잭션을 공통으로 이용한다. 이 개념은 나중에 따로 포스팅으로 다루도록 하겠다.
스프링 임베디드 데이터베이스
spring.profiles.active=test # spring.datasource.url=jdbc:h2:tcp://localhost/~/testcase # spring.datasource.username=sa # spring.datasource.password=
test에 있는 application.properties에서 spring.datasource를 전부 주석처리 해주면 db에 연결하지 않고 스프링에서 자체로 자바가 올라올 때 해당 db 테스트 케이스를 만들어주고, 자바가 내려가면 케이스를 삭제시켜준다. 메모리모드로 일시적으로 테스트해주는 것이다.
테스트를 할 때에 계속 창을 띄우지않아도 테스트 코드가 잘 작동하는지 확인할 수 있다.
'스프링 > 스프링 기초DB' 카테고리의 다른 글
스프링 데이터 JPA (0) 2023.03.26 데이터 접근 기술 - JPA (0) 2023.03.26 스프링 예외 추상화 (0) 2023.03.19 체크 예외, 언체크(런타임) 예외 (0) 2023.03.19 DB 트랜잭션 - 자동 커밋, 수동 커밋 / DB 락 (0) 2023.03.14