이전 포스팅에서는 Docker Compose를 사용하여 개발 환경에서 사용할 PostgreSQL Replication을 구성하고, Spring Boot 어플리케이션에서 Multi Data Source를 트랜잭션의 성격에 따라 Routing 하는 코드를 작성해보았다. (자세히 보기)
이번 포스팅에서는 그 코드가 의도한대로 동작하는지 통합 테스트 환경을 구축하여 테스트 코드로 검증하고자 한다.
단위 테스트를 통해 데이터베이스, 메시징 시스템 등과 같은 외부 서비스로부터 격리하여 비즈니스 로직 및 구현 세부사항을 테스트할 수 있다.
하지만, 여전히 외부 서비스와 강한 의존성을 가지고 있는 코드의 경우
단위 테스트만으로 코드를 검증하는데에는 무리가 있다.
그 예로, 위에서 언급했던 Multi Data Source Routing을 위해 작성한 코드을 떠올려 보자.
데이터베이스라는 외부 서비스와 강한 의존성을 가지고 있기 때문에
개발 환경과 동일하게 구축된 데이터베이스와 연동된 테스트 환경에서 테스트를 수행해야 유의미한 결과를 도출할 수 있을 것이다.
그렇다면, 개발 환경에서 구축한 데이터베이스와 동일한 환경에서 테스트하려면 어떻게 해야할까?
사용할 수 있는 방법들은 다음과 같다.
실제로, 개발 경험이 지금보다 훨씬 적었을 때 내가 사용했었던 방법이다.
이 방법은 관점에 따라 번거롭고도 간단한 방법이다.
결론부터 말하자면, 이 방법은 사용하지 않을 것이다.
다음과 같은 상황이라면 고려해볼 수는 있겠지만,
이렇게 작성했지만 역설적이게도(?),
나는 테스트 환경 구축을 위한 다른 도구를 사용하는 방법을 익히는 것보다 이 방법이 훨씬 번거롭다고 생각한다.
직접 외부 서비스(DBMS, Kafka, Nginx...등)를 설치해 사용할 경우 다음과 같은 크리티컬한 단점이 있기 때문이다.
개발하려는 프로젝트가 팀 프로젝트인 경우, 모든 팀원의 PC에 설치해야 한다.
CI의 이점을 사용할 수 없다.
이 방법은 프로젝트에 인메모리 데이터베이스 의존성을 추가하고, 설정 파일에 연결 정보만 작성하면 되므로, 간단하다.
또한, 스프링부트 어플리케이션이 실행될 때 H2 데이터베이스가 자동으로 시작되기 때문에 CI를 구축하여 테스트를 자동화할 수 있다.
하지만, 이 방법에도 다음과 같은 단점이 존재한다. (참고 링크)
- 호환성 문제
개인적으로, 배포 환경과 개발 환경은 기본적으로 동일해야 하고,
더 나아가 테스트 환경 역시 개발 환경과 동일해야 비로소 테스트 결과를 신뢰할 수 있다고 생각한다.
따라서, 이 방법도 PASS
spring boot 3.1 버전부터 spring-boot-docker-compose 모듈을 제공하기 때문에,
테스트 실행 전 컨테이너를 직접 띄우거나, 테스트 종료 후 컨테이너를 직접 종료할 필요가 없어졌을 뿐만 아니라,
ConnectionDetails 추상화를 통해 설정 파일에 연결 정보를 작성하지 않아도 자동으로 데이터베이스에 접속 가능하다.
TestContainers의 대부분의 이점을 해당 모듈에서도 제공하기 시작하면서 둘 중에 어떤 방법을 사용할 지 많이 고민했다.
다른 블로그에서 TestContainers를 사용하는 이유를 꼽으면서, 소개한 Docker Compose의 단점은 주로 아래와 같았다.
그러나, spring boot 3.1 버전부터 spring-boot-docker-compose 모듈이 제공되면서
2, 3, 4번 문제는 해결되었고
개발 환경의 데이터베이스를 PostgreSQL Replication으로 구성하였기 때문에 TestContainers를 사용하더라도, Docker Compose 파일을 작성해야하므로 1번 문제는 고려 대상에서 제외되었다.
또한, TestContainers와 spring-boot-docker-compose에서 제공하는 ConnectionDetails 추상화는 내가 사용하고자 하는 postgres/bitnami
이미지에 대해서는 지원하지 않는다.
( * labels를 사용하여 이름을 postgres로 지정하면 데이터베이스 자동 연결 기능을 사용할 수 있다.)
결국 5번 문제를 제외하고 두 방법에서 취할 수 있는 이점은 비슷해보인다.
TestContainers는 테스트 메소드가 수행될 때마다 컨테이너를 새로 시작할 수 있기 때문에 멱등성을 보장하고, 병렬 컨테이너 시작을 지원하기 때문에 테스트 수행 시간을 줄일 수 있다.
반면, Docker Compose는 @SpringBootTest가 붙은 테스트 클래스가 실행될 때 컨테이너를 실행하기 때문에 멱등성을 유지하기 위해서 추가적인 코드를 작성해야 하며, 병렬 컨테이너 시작을 지원하지 않는다.
또한, 테스트 환경에 PostgreSQL만 구축하고 끝낼게 아니라 다른 외부 서비스들도 추가 될 예정이기 때문에 다양한 모듈을 제공하는 TestContainers를 사용하는 것이 확장성 측면에서 더 좋을 것이라고 판단했다.
이러한 이유로 나는 TestContainers를 사용하여 테스트 환경을 구축하기로 결정했다 !