본문 바로가기
Artificial Intelligence/60. Python

[PYTHON] TDD를 넘어선 Property-based Testing : Hypothesis 라이브러리 심층 가이드

by Papa Martino V 2026. 2. 20.
728x90

Property-based Testing
Property-based Testing

1. 서론: 예제 기반 테스트(Example-based Testing)의 한계

우리가 흔히 사용하는 TDD(Test-Driven Development)나 일반적인 단위 테스트는 대부분 '예제 기반'입니다. 개발자가 직접 assert add(1, 2) == 3과 같은 특정 입력값과 기대 결과값을 정의합니다. 하지만 인간의 상상력에는 한계가 있으며, 경계값(Edge Case)이나 복잡한 데이터 조합에서 발생하는 버그를 모두 예측하기란 불가능에 가깝습니다. 이러한 한계를 극복하기 위해 등장한 개념이 바로 속성 기반 테스트(Property-based Testing)입니다. 특정 입력값이 아니라, "이 함수에 어떤 정수 리스트가 들어와도 항상 정렬된 상태여야 한다"와 같은 프로그램의 '속성(Property)'을 정의하고, 수천 가지의 무작위 케이스를 컴퓨터가 직접 생성하여 검증하게 만드는 방식입니다. 파이썬에서는 Hypothesis 라이브러리가 이 분야의 독보적인 표준입니다.


2. 예제 기반 테스트 vs 속성 기반 테스트 비교

기존 방식과 Hypothesis를 이용한 방식의 핵심 차이점을 분석하면 다음과 같습니다.

구분 예제 기반 테스트 (Pytest 등) 속성 기반 테스트 (Hypothesis)
테스트 데이터 개발자가 수동으로 작성 전략(Strategy)에 따라 자동 생성
검증 방식 특정 입력에 대한 결과값 비교 입력이 변해도 유지되어야 하는 속성 검증
엣지 케이스 탐지 개발자의 직관에 의존 무작위 및 경계값 조합으로 자동 탐지
실패 시 대응 실패한 값만 알려줌 Shrinking 기법으로 최소 실패 케이스 제공
신뢰도 작성된 예제 범위 내에서만 보장 수만 가지 시나리오를 통한 광범위한 보장

3. Hypothesis의 핵심 기능: Shrinking (축소)

Hypothesis의 가장 강력한 장점 중 하나는 Shrinking입니다. 만약 10,000개의 요소를 가진 리스트에서 버그가 발생했다면, Hypothesis는 이를 수천 번 반복 수정하여 버그가 발생하는 가장 작은 단위의 입력값(예: 요소가 2개인 리스트)을 찾아내어 리포트합니다. 이는 개발자가 디버깅 시간을 획기적으로 줄여주는 결정적인 역할을 합니다.


4. Sample Example: 이진 탐색 알고리즘 검증

이진 탐색은 정렬된 리스트를 전제로 합니다. 일반적인 테스트라면 [1, 3, 5] 정도를 넣어보겠지만, Hypothesis를 쓰면 어떤 리스트가 들어와도 안전한지 확인할 수 있습니다.


from hypothesis import given, strategies as st

def binary_search(arr, target):
    """이진 탐색 샘플 구현 (버그가 있을 수 있음)"""
    low, high = 0, len(arr) - 1
    while low <= high:
        mid = (low + high) // 2
        if arr[mid] == target:
            return mid
        elif arr[mid] < target:
            low = mid + 1
        else:
            high = mid - 1
    return -1

@given(st.lists(st.integers()).map(sorted), st.integers())
def test_binary_search_properties(arr, target):
    # 1. 속성: 원소가 리스트에 있다면 반드시 인덱스를 찾아야 함
    result_index = binary_search(arr, target)
    if target in arr:
        assert arr[result_index] == target
    # 2. 속성: 원소가 없다면 결과는 항상 -1이어야 함
    else:
        assert result_index == -1

# 실행 시 Hypothesis는 빈 리스트, 중복 리스트, 매우 큰 수 등을 자동으로 대입합니다.

5. 전문적인 도입 제언: 언제 사용할 것인가?

모든 테스트를 Hypothesis로 작성할 필요는 없습니다. 하지만 다음과 같은 비즈니스 로직에는 반드시 도입을 검토해야 합니다.

  • 인코딩/디코딩: 데이터를 변환했다가 다시 되돌렸을 때 원래 데이터와 일치해야 하는 경우 (Round-trip property).
  • 복잡한 계산 엔진: 금융 수식, 통계 알고리즘 등 입력값의 범위가 넓은 경우.
  • 데이터 유효성 검사: 사용자 입력 폼의 정규식이나 제약 조건 검증.

시니어 엔지니어로서 조언하자면, TDD로 핵심 해피 패스(Happy Path)를 구축한 뒤, Hypothesis를 통해 시스템의 견고함(Robustness)을 마무리하는 전략이 가장 효율적입니다.


6. 결론

Hypothesis는 단순히 테스트를 자동화하는 도구를 넘어, 개발자가 코드를 바라보는 관점을 '구현'에서 '명세'로 확장시켜 줍니다. "무엇이 일어나는가"보다 "무엇이 변하지 않아야 하는가"에 집중할 때, 비로소 버그 없는 무결성 소프트웨어에 가까워질 수 있습니다.


내용 출처 및 참고 자료

  • Hypothesis Official Documentation: https://hypothesis.readthedocs.io/
  • "Property-Based Testing in Python with Hypothesis" by David R. MacIver.
  • "QuickCheck: A Lightweight Tool for Random Testing of Haskell Programs" (Conceptual Foundation).
728x90