테스트 코드... 왜 필요해?

Bobby·2023년 11월 23일
0

즐거운 개발일지

목록 보기
21/22

🤷🏻‍♂️ 테스트 코드 꼭 필요할까...

귀찮음..어려움..시간없음..

개발을 하면서 테스트의 중요함에 대해서 많이 들어왔다.

하지만 적용하기란 쉽지않다.

테스트 코드 없이 개발되어 유지되고 있는 커다란 프로젝트에 테스트 코드를 도입하는게 많은 비용이 들기 때문이다.

동료들의 동의와 학습도 필요하고 할 시간이 없다. 기능 개발하기도 바쁜데 수많은 기존 코드들의 테스트 코드까지 짜야 한다고..?

충분한 학습과 의지가 없으면 사실 테스트 코드 자체가 짐덩어리가 되는 경우도 생기기도 한다.


🤦🏻‍♀️ 그럼에도 불구하고 테스트 코드가 마려운 순간이 있다.

  1. 신규 기능을 개발할 때 기존 로직을 수정해야 하거나 공통으로 사용하는 부분을 수정하는 상황이 오면 겁난다. 다른 API들에 영향을 얼마나 미칠지 모르기 때문이다.

  2. 테스트 코드가 없을 때의 리팩토링은 정말 큰 작업이다. 관련 된 부분의 전체 테스트가 필요하다.

  3. 회기 버그가 발생하기도 하고 기존에 테스트 했던 영역을 또 테스트를 해야할 때도 있다. 그래서 서비스 커질 수록 QA기간도 늘어나고 배포가 불안하다.

개발하다보면 사실 기능 개발보다 디버깅에 더 많은 시간이 소요된다.

테스트 코드가 없으면 디버깅 시간이 늘어난다. -> 개발에 집중할 수 있는 시간이 줄어든다. -> 실수 확률이 올라간다. -> 개발 시간이 더 소요된다 -> 테스트 코드 짤 시간이 부족해진다. -> ...

악순환이다.

그럴 때마다 테스트 코드가 잘 짜여져 있다면 어땠을까 하는 생각이 든다.


🙆 이제는 해볼까..?

시도하지 않으면 변하는 것은 없다!

그러다 개인적으로라도 테스트 코드를 짜보자는 생각이 들었다.

테스트 코드가 없는 프로젝트라면 레이어드 아키텍처로 구성되어 있을 확률이 높다.
테스트 코드가 익숙하지 않으니 어떻게 시작해볼까 고민을 하다가 비즈니스 레이어의 통합테스트로 시작해 보기로 했다.

기존 개발 프로세스를 보자면

  1. 신규 API 개발 또는 기존 기능 수정 완료
  2. 로컬환경에서 서버 실행 후
  3. http클라이언트(포스트맨, 인텔리제이 http 등)를 사용해서 API호출 후 동작 확인
  4. 버그 또는 에러 발생하면 수정 하고 서버 재실행
  5. API 호출 하고 동작 확인
  6. 반복

처음엔 괜찮았지만 서비스가 커지고 API가 많아지면 로컬에서 서버 돌리는데도 시간이 걸리고 몇 번 재실행 하다보면 답답하다. 서버 실행 완료 될 때까지 기다렸다가 API호출 해야 하니 귀찮다.

그래서 첫 시작은 내가 짠 로직을 요구사항대로 잘 동작하는 지에 대한 자동 검증을 위한 테스트 코드가 아니고 내가 짠 로직을 실행해보는 것에 목적을 둔 테스트 코드로서 사용했다.

예를 들면 이런식으로

@SpringBootTest
class OrderServiceTest {

    @Autowired
    private OrderService orderService;

    @Test
    @DisplayName("주문을 생성한다.")
    void createOrder() {
        
        // 요청 파라미터
        OrderCreateRequest request = createOrderRequest();

        // 서비스 메소드 실행
        OrderResponse result = orderService.createOrder(request);

		// 응답 출력
        System.out.println("result = " + result);
    }

}

개발DB 환경에서 테스트 코드 실행 후 응답 값을 직접 눈으로 보고 버그를 찾고 수정하고 다시 테스트코드 실행을 반복하면서 개발했다.

테스트 코드로서의 역할은 전혀 하지 못했지만 이렇게만 하더라도 서버실행과 API 호출을 동시에 할 수 있었기 때문에 생산성 향상을 느낄 수 있었다.

이렇게 테스트 코드를 짜는 것을 시작해 테스트환경을 분리하고(H2 메모리DB) 검증 로직을 추가해 통합테스트를 작성했다.

간단하게 예를 들면

@SpringBootTest
class OrderServiceTest {

    @Autowired
    private ProductRepository productRepository;

    @Autowired
    private OrderService orderService;

	...
    

    @Test
    @DisplayName("주문을 생성한다.")
    void createOrder() {
        // given
        Product product1 = createProduct();
        Product product2 = createProduct();
        Product product3 = createProduct();
        productRepository.saveAll(List.of(product1, product2, product3));

        OrderCreateRequest request = createOrderRequest();
        
        ...

        // when
        OrderResponse result = orderService.createOrder(request);
        
        // then
        assertThat(result.getId()).isNotNull();
        assertThat(result.getTotalPrice()).isEqualTo(5000);
        
        ...
        
    }
}

통합테스트만 작성하더라도 만족스러웠다.


🍖 이제 욕심이 더 생기기 시작한다.

단위테스트를 추가하기 시작하면 고민이 많아진다.
주문 같은 핵심 도메인에 대한 중요한 로직먼저 단위테스트를 추가해본다.

  • 외부 API 호출하는 것은 어떻게하지?
  • mock 만들때는 Mockito를 사용할까? 아니면 Fake클래스를 만들어서 할까?
  • LocalDateTime.now()나 랜덤값 생성 같은 로직에 대한 테스트는 어떻게 하지?
  • ...

테스트 코드 작성이 어렵고 귀찮아 지면서 아키텍쳐를 개선하려고 생각하게 된다.

객체 간의 의존성을 약하게 만들기도 하고(인터페이스), 쓸데없는 의존성 주입을 줄이기도 하고 상위 계층을 의존하고 있는 부분들을 찾아내기도 한다.

결국 테스트를 쉽게 하기 위해 고민 하다보면 좋은 방향으로 가게 되더라.

"한 번 시작하고나면 presentation계층, persistence계층 테스트에 손을 대고 있는 자신을 발견할 것이다. 그러다 DDD, 아키텍처에 관심을 가지게 될 것이다."


🎅🏻 뜻 밖의 이득..!

이렇게 하나 둘씩 테스트가 많아지면 많아 질 수록 의외의(?) 좋은점이 있다.

테스트 자체가 코드로 된 정책이자 문서가 된다는 점이다.

해당 도메인에 대한 정책 등 정보가 부족하면 다른사람이 짠 코드 보기 쉽지않다. 그런데 테스트 코드가 잘 짜여저 있다면 테스트 코드만 봐도 이해하기 쉬워진다.

예를 들면

@Test
@DisplayName("로그인 시 5번 이상 실패하면 로그인 제한 상태가 된다.")
void login_fail() {

    ...

}

이 테스트 코드를 보면 로그인 제한 정책을 쉽게 알 수 있다.

@Test
@DisplayName("재고가 부족한 상품을 주문 할 경우 예외가 발생한다.")
void createOrder_fail() {
    
    ...
     
}

이 테스트코드를 보면 어떤 상황에서 어떤 예외가 발생하는지 쉽게 알 수 있다.

잘 짜여진 테스트 코드를 읽는 것으로 어떤 상황에 어떤 흐름으로 어떤 동작을 하고 어떤 결과가 나오는지 이해하는데 도움이 된다.


🧚‍♀️ 테스트의 끝은 TDD?

테스트 하면 TDD를 빼놓을 수 없다.

비즈니스 로직 구현 -> 테스트 코드 작성

  • 비즈니스 로직이 복잡하면 복잡할 수록 예외 케이스에 대한 테스트 코드를 놓치는 부분이 생기기 쉽다. (바빠서 귀찮고 빼먹는 일도 생길 수도..?)

테스트 코드 작성 -> 비즈니스 로직 구현(red -> green -> refactoring)

  • 테스트 코드를 먼저 작성하면서 로직을 구현하고 리팩토링 하기 때문에 해당 로직이 구현이 되어있다면 테스트 코드가 있다는 것이 보장된다.

익숙해 진다면 신뢰성있는 소프트웨어를 개발하는데 도움이 될..지도?


💁🏻 한줄요약

테스트 코드 시작하자!

profile
물흐르듯 개발하다 대박나기

0개의 댓글