테스트시 유의해야 할 점 두가지가 있다.

  1. 테스트는 다른 테스트와 격리해야 한다.
  2. 테스트는 반복해서 실행할 수 있어야 한다.

1번사항의 같은 경우는 간단하게 생각하면 DB를 나누면 되겠지만, 2번은 DB를 나누어도 만약 save() 같은 로직을 여러번 실행했을 때 DB 중복 때문에 반복해서 실행하기는 힘들 것이다!

즉 반복해서 실행하면서 테스트 코드 수정 자체에 온 힘을 들일 수 있는 환경이 필요하다.

해결법은 바로 트랜잭션 롤백 전략이다. 그렇다 한 트랜잭션 안에서는 즉 같은 커넥션 안에서는 자신의 DB 쿼리 변경사항을 확인할 수 있기에, save(), findById(), delete() 를 한번에 수행이 가능할 것이다!

테스트 코드에서 트랜잭션 롤백 전략을 수행할 수 있는 방법은 여러가지 가 있는데, 천천히 디벨롭해 나가겠다.

@SpringBootTest
class ItemRepositoryTest {

    @Autowired
    ItemRepository itemRepository;

    @Autowired
    PlatformTransactionManager transactionManager;
    TransactionStatus status;

    @BeforeEach
    void beforeEach() {
        //트랜잭션 시작
        status = transactionManager.getTransaction(new DefaultTransactionDefinition());
    }

    @AfterEach
    void afterEach() {
        //MemoryItemRepository 의 경우 제한적으로 사용
        if (itemRepository instanceof MemoryItemRepository) {
            ((MemoryItemRepository) itemRepository).clearStore();
        }
        //트랜잭션 롤백
        //transactionManager.rollback(status);
    }

@BeforeEach : 각각의 테스트 케이스를 실행하기 직전에 호출된다. 따라서 여기서 트랜잭션을 시작하면 된다. 그러면 각각의 테스트를 트랜잭션 범위 안에서 실행할 수 있다. PlatformTransactionManager 로 트랜잭션을 시작한다.

@AfterEach : 각각의 테스트 케이스가 완료된 직후에 호출된다. 따라서 여기서 트랜잭션을 롤백하면 된다. 그 러면 데이터를 트랜잭션 실행 전 상태로 복구할 수 있다. PlatformTransactionManager 로 트랜잭션을 롤백한다.

2번째 방법으로는 (그냥 이거 쓰자!)

@Slf4j
@Transactional
@SpringBootTest
class ItemRepositoryTest {

    @Autowired
    ItemRepository itemRepository;
}