안녕하세요 이번글은 프로젝트 Unit 테스트코드와 Integration 테스트코드 작성시 발생했던 문제에대해서 작성하였습니다.
문제상황
팀원분이 했던 코드를 PULL를 받고 테스트를 돌리던중 발생했던문제가있습니다.
- 팀원분의 Redis포트번호가 저와 다르기때문에 발생했습니다.
- Redis는 테스트 코드 실행 후 롤백이 불가능하므로 깨지는 테스트가 존재했습니다.
생각한 방법
방법1. Docker컨테이너를 테스트코드를 실행하고 나서 Redis 컨테이너 삭제하자.
왜냐하면 레디스는 롤백이없기때문에 테스트를 종료시키는게 좋다고생각했습니다.
그런데 이 방법은 개발자가 직접 매번 작동해야한다면 이것은 매우 불편한 일입니다.
즉 향후 CI / CD도입을 하는데 도입의 목적은 자동화를 도입시켜 생산성을 향상시키는데 있는데 도입목적과 다르다고생각했습니다.
방법2. 운영환경과 동일한 Test환경을 구축하는것입니다.
방법1과 방법2중에서 방법2를 선택하는게 가장좋지만 비용적인 문제가 따르기 떄문에 저희는 방법1을 자동화해주는 TestContainer라는것을 알게되었습니다.
테스트 컨테이너는 자바 라이브러리인 Junit 테스트를 지원해준다고합니다.
Junit5가 전제 조건 환경입니다. 그래서 저희 개발환경은 Junit5를 사용하기때문에 매우 적합하다고생각했습니다.
공식문서에서는
"모든 개발자와 CI 시스템에 Redis가 설치되어 있다고 확신하는 경우 작동할 수 있지만 그렇지 않으면 실패합니다.
테스트 간 포트 충돌과 같이 테스트를 병렬로 실행하려고 하면 문제가 발생할 수도 있습니다"
이러한 문제를 테스트컨테이너로 개선하는 방법이라고 말해주고있습니다. 그래서 저희의 문제와 일치하다고 생각되어서 도입에 확신을 가졌습니다.
TestContainer란?
Testcontainers는 테스트에서 도커 컨테이너를 자동으로 띄워주고 테스트가 종료되면 컨테이너도 종료해주는 라이브러리입니다.
사용하면서 겪었던문제
문제상황.
스프링부트가 시작되면서 빈을 생성시 레디스에대한 properies가 다음과 설정되어있는데 저부분에 레디스가 사용되지않기때문에 빈생성이 되지않았기때문에 connection에러가 발생했습니다.
spring.redis.cart.port=6679
테스트컨테이너의 실행순서가 테스트 컨테이너를 먼저 실행하고 스프링이 작동하는 것을 터미널을 보면서 알았습니다.
그래서 도커를 통해 실행때 생성되는것을 파악하였고 포트번호를 확인하니 랜덤하게 포트번호가 배정되는것이었습니다.
그래서 레디스 연결이 되지않았던 것입니다.
다음과 같이 실행될때 테스트 컨테이너가 먼저실행되기때문에 properties를 바꾸는방법이었습니다.
@Container
static GenericContainer redisContainer = new GenericContainer("redis")
.withExposedPorts(6379);
static class ContainerPropertyInitializer implements ApplicationContextInitializer<ConfigurableApplicationContext> {
@Override
public void initialize(ConfigurableApplicationContext context) {
TestPropertyValues.of("spring.redis.cart.port=" + redisContainer.getMappedPort(6379))
.applyTo(context.getEnvironment());
}
}
+ 향후 결합도를 낮추기위해 아래와 같이 변경했습니다.
왜냐하면 기존 코드는 매번 테스트 클래스마다 설정해줘야하는 반복되는 부분이 존재했습니다.
그래서 만약 코드가 변경된다면 전체를 바꿔줘야하기 때문에 결합도를 낮추기위해 어노테이션을 사용했습니다.
장점
테스트컨테이너의 장점은 운영 환경을 동일하게 구성하고 컨테이너를 제거해주기때문에 테스트후에 리소스를 먹지도 않고 저희가 목표로하는 테스트를 운영환경과 동일환경에서 돌릴 수 있도록해주는 장점이있습니다.
단점
테스트시 컨테이너를 만들고 실행, 삭제 하기때문에 기존보다 많이 느려졌습니다.
테스트코드는 정확성이 더 중요해서 느려도 된다고 생각했지만 제가 느낀것은
만약 회사에서는 더 규모가 커질것이고 테스트시간이 테스트컨테이너로 인해 5분이 추가적으로 걸린다면 많은 사람들이 테스트를 돌린다면 한사람당 5분씩이기때문에 10명이면 50분 시간을 잡아먹을수도있습니다.
결론
그래도 현재로서는 비용적인 측면에서 저희에게 트레이드오프로는 비용절약이 되지만 시간이 조금더 걸렸습니다. 그치만 저희에게는 비용부분은 매꿀수없기때문에 테스트컨테이너를 도입했습니다.
느낀점
테스트컨테이너의 장점은 환경을 동일하게 구성하고 컨테이너를 제거해주기때문에 테스트후에 리소스를 먹지도 않고 저희가 목표로하는 테스트를 동일환경에서 돌릴 수 있도록해주는 장점이있습니다
문제를 해결하기위해 알아보던중
테스트컨테이너를 들어본적이 있기때문에 기술을 금방 알아보고 도입할수있게되었습니다.
왜냐하면 저는 테스트코드 작성에 대해 매우 관심이많았습니다. 여러 래퍼런스들을 읽어보다가 우연히 한번 봤던경험이있었기때문입니다.
그래서 페이스북에 생활코딩이나 레퍼런스나 Medium에 글들을 당장의 저에게는 필요가 없지만 한번씩 읽어보기라도 한다면 나중에 TestContainer를 도입한것처럼 한번 흠칫 들었던 경험을 통해 찾아보고 도입할수있기때문에 시간날때 한번씩 읽어보고 최신트렌드를 알보는 습관을 가져야겠다고 느꼈습니다.
https://www.testcontainers.org/
'Delivery' 카테고리의 다른 글
캐시 적용으로 읽기 성능 향상 (0) | 2022.09.08 |
---|---|
FCM 푸시알림 구현 이슈 - 비동기 처리(성능개선) (0) | 2022.08.23 |
Redis 장바구니 - 2 (Redis pipelining) (0) | 2022.08.18 |
Redis를 이용한 장바구니 - 1 (0) | 2022.08.15 |
리펙토링 디비조회 (0) | 2022.08.09 |