서론
과제 요구사항을 구현하며, 비동기로 로직을 처리해야하는 작업이 필요했다.
해당 로직을 검증하기위해 테스트 코드를 작성하며 다양한 시행착오가 있었는데, 이를 글로 정리해보고자 한다.
본론
요구사항은 특정 API로부터 데이터를 가져와 필요한 데이터를 DB에 저장하는 로직이였는데,
특정 API로부터 응답 시간이 오래 걸리기 때문에
그동안 Connection을 유지하는건 리소스 낭비라고 생각하여 비동기로 구현을 해야겠다고 생각을 했다.
@Async를 이용하여 비동기로 구현을 했고, 이제 테스트 코드를 통해 검증을 해야했는데 예상치 못한 문제가 발생했다.
기존에는 ServiceTest라는 최상위 클래스에서 @Transactional을 선언하여 테스트 데이터가 테스트 이후 Rollback되었는데, @Async를 선언한 메서드를 호출하면 새로운 Thread를 생성하여 비동기로 실행을 하기 때문에 독립적인 트랜잭션이 실행되어 기존의 트랜잭션에 영향을 받지 않게되고, @Transactional에 의거하여 롤백이 진행되지 않게되었다.
테스트 격리를 위해서 @ActiveProfiles를 이용하여 yml 파일을 분리시켜 테스트를 진행했고,
테스트별로 DB 초기화를 위해 test 환경의 yml파일의 ddl-auto 옵션을 create로 설정하여 진행을 하였다.
하지만 해당 설정은 최초 스프링이 로드 될 때에만 적용이 되었고,
모든 단위 테스트를 돌리는 테스트에서 테스트별로 DB 초기화가 필요했기 때문에 해당 설정만으로는 불가능하였다.
결국 테스트별 DB 초기화를 위해 방법들을 찾아보던 중 향로님의 글을 보고 명시적 데이터 초기화를 적용하여 문제를 해결 할 수 있었다.
테스트 데이터 초기화에 @Transactional 사용하는 것에 대한 생각 (tistory.com)
CleanUp이라는 클래스에 @Component를 이용하여 Bean으로 등록하였고
all 이라는 메서드를 통해 관련 테이블들을 Truncate시켜 데이터를 초기화시켜주었다.
하지만, 단순 Truncate만 시키니 제약조건 관련 Exception이 떴고,
향로님께서는 이를 위해 테이블 관계에서는 FK 제약조건을 끊고, Application의 도메인 로직으로만 엮어야 테스트 데이터 초기화가 쉽다고 하셨지만,, 지금 당장 설계를 바꿀 순 없었기 때문에 Truncate 전 후로 제약조건 무효화 후 재설정을 시켜주었다.
[h2] h2 db에서 제약조건 제거하고 테이블 초기화 & 삭제하기 :: 섭이의 개발일지 (tistory.com)
@Component
@RequiredArgsConstructor
public class CleanUp {
private final JdbcTemplate jdbcTemplate;
public void all() {
// 제약조건 무효화 -> 데이터 초기화 -> 제약조건 재설정
jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY FALSE");
jdbcTemplate.execute("TRUNCATE TABLE REFRESH_TOKEN");
jdbcTemplate.execute("TRUNCATE TABLE MEMBER");
jdbcTemplate.execute("SET REFERENTIAL_INTEGRITY TRUE");
}
이제 빈으로 등록을 시켰으니 Test 코드에서 호출을 해보자.
@SpringBootTest
@ActiveProfiles("test")
class MemberServiceTest {
@Autowired
CleanUp cleanUp;
@AfterEach
void afterEach() {
cleanUp.all();
}
''' 테스트 코드
}
빈으로 등록한 CleanUp 클래스를 DI 시킨 후 @AfterEach에서 호출을 해주었고,
테스트 케이스가 원하는대로 정상적으로 수행이 됨을 확인 할 수 있었다.
결론
테스트 코드들을 작성하며, 로직을 위한 설계도 중요하지만
테스트를 고려한 설계도 중요하단것을 다시 한 번 깨달았다.
'💻Spring' 카테고리의 다른 글
Spring boot 3.2에서 Aws Sqs Temporary Queue를 이용한 요청 응답 구현하기 (2) | 2024.03.20 |
---|---|
WebClient를 활용한 병렬 API 호출 및 예외 처리 (0) | 2024.02.19 |
Swagger 3 (springdoc-openapi-ui) 에서 @AuthenticationPrincipal 파라미터 무시 전역 설정 (0) | 2024.01.05 |
Spring WebClient를 이용한 Open API 통신 (0) | 2023.12.11 |
Spring Boot에서 Batch, Scheduler 사용기 (0) | 2023.12.08 |