[단위 테스트] 원칙과 패턴 (6장) - 단위 테스트 스타일

2025. 4. 17. 15:36·기타

단위 테스트의 목적은 코드 품질을 보장하는 데 있습니다. 그러나 무엇을 테스트할 것인가, 어떻게 테스트할 것인가에 따라 테스트의 유지보수성과 신뢰도는 크게 달라집니다.
이 글에서는 단위 테스트의 세 가지 스타일(출력 기반, 상태 기반, 통신 기반)과 함수형 아키텍처가 테스트 용이성에 어떤 영향을 주는지를 함께 살펴봅니다.


단위 테스트 스타일 3가지

단위 테스트는 System Under Test(SUT)에 대한 입력과 결과를 검증하는 방식으로 진행되며, 일반적으로 다음의 세 가지 스타일로 나뉩니다.

1. 출력 기반 테스트 (Output-Based Testing)

출력 기반 테스트는 SUT에 입력을 주고, 반환된 결과값을 검증하는 방식입니다.
이 방식은 다음과 같은 특징을 가집니다:

  • 숨은 입출력이 없다는 가정 하에 동작
  • 테스트가 작고 간결하며 유지보수가 쉬움
  • 내부 구현에 거의 의존하지 않아 리팩터링에 강함
assertThat(calculator.add(2, 3)).isEqualTo(5);

출력 기반 테스트는 테스트 품질이 가장 뛰어난 스타일로 평가받습니다.


2. 상태 기반 테스트 (State-Based Testing)

SUT가 동작한 이후의 시스템 상태를 검증하는 방식입니다. 객체의 내부 상태나 DB 상태 등을 확인할 때 사용됩니다.

  • 비공개 상태를 테스트하지 않도록 주의해야 함
  • 테스트 크기가 커지고 유지보수가 어려울 수 있음
  • 헬퍼 메서드나 값 객체로 복잡도 완화는 가능하지만 근본적 해결은 어려움

3. 통신 기반 테스트 (Interaction-Based Testing)

SUT와 협력자 사이의 메시지 전달 여부나 방식을 검증합니다. 주로 Mock 객체를 활용합니다.

  • 외부와의 통신이 있는 경우에 적절 (이벤트 발행, API 호출 등)
  • 테스트 코드에 목 객체가 많아져 가독성 저하 가능
  • 시스템 경계를 넘는 통신만 검증하는 것이 바람직

고전파 vs 런던파의 테스트 스타일 선호

고전파 (Classicist) 상태 기반 테스트 선호
런던파 (Londonist) 통신 기반 테스트 선호
공통 출력 기반 테스트는 모두 선호

함수형 프로그래밍과 테스트 용이성

함수형 프로그래밍은 수학적 함수의 개념을 따릅니다.
수학적 함수는 숨은 입력이나 출력이 없는 함수입니다.

  • 숨은 출력: 예외, 로그 출력, DB 반영 등 사이드 이펙트
  • 숨은 입력: 전역 변수, 외부 상태 참조

이러한 순수 함수의 특성 덕분에, 함수형 프로그래밍은 테스트하기 쉬운 구조를 제공합니다.


함수형 아키텍처란?

함수형 아키텍처는 시스템을 다음 두 부분으로 나눕니다:

  • 함수형 코어: 순수한 연산, 사이드 이펙트 없음
  • 가변 셸: 입력을 받고 출력(사이드 이펙트)을 처리

즉, 사이드 이펙트를 가장자리로 밀어내고 중심에는 테스트 가능한 순수 함수를 배치합니다.


함수형 아키텍처 vs 육각형 아키텍처

 

구분 함수형 아키텍처 육각형 아키텍처
사이드 이펙트 처리 도메인 밖으로 모두 밀어냄 도메인 안에서 일부 허용
테스트 용이성 높음 중간
성능 낮을 수 있음 상대적으로 유연함
적용 대상 복잡한 핵심 도메인 유연한 계층 분리가 필요한 구조

함수형 아키텍처는 테스트 용이성과 유지보수성을 최우선으로 합니다. 대신 성능이 다소 희생될 수 있습니다.


모든 코드에 함수형 아키텍처를 적용해야 할까?

아닙니다. 모든 시스템에 함수형 아키텍처를 적용하는 것은 바람직하지 않습니다.
다음과 같은 경우에 전략적으로 선택하는 것이 좋습니다

  • 도메인이 복잡하거나 변경 가능성이 높은 시스템
  • 테스트 가능성이 중요한 핵심 로직
  • 장기적으로 유지보수가 중요한 코드 베이스

반면, 단순하거나 중요하지 않은 구성 요소라면 굳이 함수형 구조를 도입하지 않아도 됩니다.


테스트와 아키텍처는 함께 고려해야 한다

출력 기반 테스트는 테스트 품질, 유지보수성, 리팩터링 내성에서 뛰어난 장점을 가집니다.
함수형 아키텍처는 이러한 테스트 스타일이 적용되기 쉬운 구조를 제공합니다.


사이드 이펙트가 가장자리에만 존재한다면, 실제 입출력은 어디서 어떻게 처리할까?

실제로 함수형 아키텍처에서는 가변 셸이 사이드 이펙트를 담당합니다.
예를 들어 다음과 같이 구분됩니다:

  • 함수형 코어: 계산, 유효성 검사, 비즈니스 규칙 판단 등
  • 가변 셸: 파일 입출력, DB 접근, API 호출, 로그 출력 등

실제로 코드에서는 다음과 같이 역할을 나눌 수 있습니다:

// 함수형 코어
int calculateDiscountRate(Customer customer) {
  if (customer.isVip()) return 20; return 5;
}

// 가변 셸
void processOrder(Order order) {
  int rate = calculateDiscountRate(order.getCustomer());
  order.applyDiscount(rate);
  orderRepository.save(order);
// DB 접근 = 사이드 이펙트
}

이처럼, 순수 함수는 예측 가능하고 테스트가 쉬우며, 사이드 이펙트는 모서리에 몰아넣어 통제 가능하게 됩니다.

'기타' 카테고리의 다른 글

[단위테스트] 원칙과 패턴 (8장) - 통합 테스트를 하는 이유  (0) 2025.04.21
[단위 테스트] 원칙과 패턴 (7장) - 단위테스트를 위한 리팩터링  (0) 2025.04.18
[단위 테스트] 원칙과 패턴 (5장) - 목과 테스트 취약성  (0) 2025.04.16
[단위 테스트] 원칙과 패턴 (4장) - 좋은 단위 테스트의 4대 요소  (0) 2025.04.15
[단위 테스트] 원칙과 패턴 (3장) - 단위 테스트 작성 원칙  (0) 2025.04.15
'기타' 카테고리의 다른 글
  • [단위테스트] 원칙과 패턴 (8장) - 통합 테스트를 하는 이유
  • [단위 테스트] 원칙과 패턴 (7장) - 단위테스트를 위한 리팩터링
  • [단위 테스트] 원칙과 패턴 (5장) - 목과 테스트 취약성
  • [단위 테스트] 원칙과 패턴 (4장) - 좋은 단위 테스트의 4대 요소
ksngh
ksngh
웹 백엔드 개발 블로그입니다. https://github.com/ksngh
  • ksngh
    featherdale
    ksngh
  • 전체
    오늘
    어제
    • 분류 전체보기 (68)
      • 데이터베이스 (10)
      • spring (11)
      • redis (7)
      • ELK (11)
      • 회고 (6)
      • 기타 (13)
        • java (2)
        • 디자인패턴 (2)
        • 영어 (1)
        • 자바스크립트 (1)
        • graphQL (2)
        • 블록체인 (1)
  • 블로그 메뉴

    • 홈
    • 태그
    • 방명록
  • 링크

  • 공지사항

  • 인기 글

  • 태그

    엘라스틱서치
    조인의 종류
    엘라스틱 서치
    Mock
    연말 회고
    Redis
    Elastic Search
    core
    대용량데이터베이스
    gof
    단위 테스트
    엘라스틱 서치 인 액션
    레디스
    NoriTokenizer
    단위테스트
    Elasticsearch
    대용량 데이터 베이스
    spring
    데이터베이스
    NORI
    nori tokenizer
    회고
    elastic search in action
    Spring Core
    자료구조
    PostgreSQL
    Spy
    graphql
    Text to SQL
    디자인패턴
  • 최근 댓글

  • 최근 글

  • hELLO· Designed By정상우.v4.10.4
ksngh
[단위 테스트] 원칙과 패턴 (6장) - 단위 테스트 스타일
상단으로

티스토리툴바