개발

테스트 코드가 막막한 개발자를 위한 가이드

devracoon 2026. 1. 26. 22:16

이 글에서는 테스트 코드를 작성할 때 고려해야하는 "무엇을 검증할 것인가"에 대한 약속인 Given-When-Then 패턴에 대해 다룹니다. 이것만 염두에 두고 테스트코드를 작성하면 테스트 코드의 구조를 잡기 쉽습니다.

 


 

테스트 코드의 공식: Given-When-Then

모든 테스트는 기본적으로 이 3단계로 구성합니다.

  1. Given (준비): 테스트를 위해 필요한 데이터나 상황을 준비합니다.
  2. When (실행): 준비된 것들로 검증하려는 알고리즘을 실행합니다.
  3. Then (검증): 실행 결과가 예상과 같은지 확인합니다.

준비하고, 실행하고, 검증한다.

어떻게 보면 테스트를 해야겠다고 느낀 순간부터 본능적으로 알고 있던 과정일지도 모릅니다.

하지만 이걸 의식하는 것이 좋은 테스트 코드 작성의 시작입니다.

 


 

어디서부터 시작할까?

'어디서부터' 라는 부분은 '어느 단계부터' 와 맞닿아 있습니다.

테스트의 종류는 다양합니다. 단위 테스트, 통합 테스트, 시스템 테스트, 인수 테스트, 운영 테스트···. 많은 테스트 단계가 있으며 조직마다 또 테스트의 정의와 범위가 다릅니다.

 

우리는 그 중에서 가장 기본이 되는 단위 테스트통합 테스트에 집중해 보도록 하겠습니다.

 


 

단위 테스트 (Unit Test)

단위 테스트는, 소스 코드의 가장 작은 단위(일반적으로 함수)가 의도대로 정확히 작동하는지 독립적으로 검증하는 테스트를 말합니다. 이 정의 중 아래 세 가지로 포인트로 잡겠습니다.

  • 함수
  • 의도대로 정확히
  • 독립적 검증

이 세 가지를 기억하며 부연설명하겠습니다.

테스트 코드를 작성할 때, 하나의 테스트 함수로 하나의 작업만 테스트하도록 작성합니다.
테스트는 서로 의존하지 않아야 합니다. 독립적으로 수행되어야 합니다.

실행하는데에 원래 필요하던 의존성까지도 분리하고, 해당 로직만 테스트합니다. (mock 등을 활용)

 


 

통합 테스트 (Integration Test)

통합 테스트는, 단위 테스트가 완료된 모듈들이 상호작용하며 전체적으로 의도된 기능을 정확히 수행하는지 검증하는 테스트를 말합니다.

통합 테스트에서는 단위 테스트에서 제거 또는 대체되었던 외부 의존성과 외부 시스템(DB나 API 등)과의 연동을 포함하여 데이터 흐름과 인터페이스의 오류를 검증하는 것이 주된 목적입니다. 

 


 

단위 테스트와 통합 테스트의 비교

구분 단위 테스트 통합 테스트
대상 순수 로직 (알고리즘, 유틸리티) 서비스 전체 흐름 (DB, API 등 포함)
속도 매우 빠름 비교적 느림
특징 외부 의존성 없음 (Mocking) 실제 외부 의존성 포함
도구 (SpringBoot) JUnit 5, AssertJ @SpringBootTest, Testcontainers

 

 

단위 테스트를 선행한 후 통합 테스트로 가는 것이 합리적이니, 먼저 단위 테스트부터 촘촘히 작성해봅시다.


 

무엇부터 테스트해야할까?

어느 단계부터 시작할지는 이제 해결됐습니다.

이렇게 해서 모든 코드를 다 테스트하면 좋겠지만, 우리에겐 항상 시간이 부족하고, 우선순위가 필요합니다.

먼저 시작하는 건 이 두 가지가 좋습니다. 

  • 성공: 입력값이 정상적이고 예상 가능한 범위일 때, 기대한 대로 동작하는가?
  • 입력값 예외: 이상한 값이 들어왔을 때 내가 설계한 에러를 잘 던지는가?

성공과 입력값 예외 케이스를 촘촘히 작성한 뒤에는, 아래 항목들도 염두에 두고 테스트 코드가 커버리지를 넓혀나가면 됩니다.

  • 상태 변화: 어떤 작업 후 데이터가 의도한 대로 변했는가? (주문 후 재고가 -1 처리 등)
  • 권한 및 보안: 비로그인 사용자나 권한 없는 사용자의 접근이 잘 차단되는가?
  • 동시성: 동시에 들어온 여러 요청에 대해 데이터 정합성을 잘 보존하는가?
  • 외부 장애: DB나 외부 API의 장애로 발생하는 예외는 안전하게 처리되는가?

 

뿐만 아니라, 스스로 "만약 이렇게 되면? 이런 상황에서도 잘 처리된거 맞나?" 하는 질문을 던지며, 내가 처리하는 이 비즈니스의 결함을 찾아내는 책임감을 가진 개발자가 됩시다.


 

테스트 코드 예시 (Java)

URL 단축 기능의 예시 테스트 코드입니다.

@Test
void URL_단축_테스트() {
    //Given: 원본 URL을 준비합니다.
    String originalUrl = "https://google.com";
    
    //When: 단축을 실행합니다.
    String shortenedUrl = urlService.shorten(originalUrl);
    
    //Then: 결과값이 비어있지 않고, 특정 규칙을 따르는지 확인
    assertThat(shortenedUrl).isNotNull();
    assertThat(shortenedUrl).startsWith("https://");
}

 


 

마치며: 테스트하기 좋은 코드를 씁시다.

테스트 코드를 짜다 보면 이런 생각이 드는 때도 있습니다.

"아,.,. 얘는 테스트 작성하는게 더 복잡한데;;"

 

이건 아마 걔가 하고있는 일이 너무 많아서일 확률이 큽니다.

알고리즘의 설계가 복잡한 것은 아닌지 확인 후, 로직을 작게 쪼개는 것이 좋습니다.

 

한 가지 일만 하는 로직은 테스트하기 쉽습니다. 그리고 테스트하기 쉬운 코드가 곧 좋은 코드입니다.