테스트 상속의 숨은 비용

카테고리

프로그래밍/소프트웨어 개발

서브카테고리

개발 툴

대상자

  • 소프트웨어 개발자, QA 엔지니어
  • 파이썬 unittest 프레임워크 사용자
  • 테스트 코드 유지보수에 관심 있는 개발자
  • 난이도: 중간 (테스트 설계 패턴 이해 필요)

핵심 요약

  • 테스트 상속 패턴은 유지보수성과 디버깅 편의성을 상실하게 만든다
  • del BaseAnimalTests로 인해 테스트 메서드 위치 추적 불가능
  • super().test_speak()로 인한 복잡한 디버깅 프로세스
  • 파이썬 pytest.mark.parametrize가 테스트 재사용성과 가독성을 동시에 제공
  • @pytest.mark.parametrize('animal_class', [Armadillo, Okapi]) 사용 예시
  • DRY 원칙은 테스트에서는 가독성과 명확성보다 우선시 되어야 한다

섹션별 세부 요약

1. 테스트 상속 패턴의 문제점

  • 코드 중복 감소는 유지보수성 저하로 이어짐
  • BaseAnimalTests 삭제 후 테스트 메서드 추적 불가
  • IDE에서 test_speak 메서드 검색 실패
  • CI 환경에서의 오류 추적 어려움
  • AssertionError: 0 not greater than 0 발생 시 원인 파악 불가
  • Search everywhere 기능으로도 테스트 위치 찾기 어려움

2. 대안 패턴: `pytest.mark.parametrize`

  • 동일한 테스트 로직을 파라미터로 재사용 가능
  • ```python

@pytest.mark.parametrize('animal_class', [Armadillo, Okapi])

def test_speak(animal_class):

sound = animal_class().speak()

assert isinstance(sound, str)

assert len(sound) > 0

```

  • 테스트 결과 명확성 향상
  • test_speak[Armadillo] FAILED / test_speak[Okapi] PASSED
  • 실패한 테스트만 재실행 가능

3. `parameterized_class` 사용 예시

  • parameterized 라이브러리 활용

```python

from parameterized import parameterized_class

@parameterized_class([{'animal_class': Armadillo}, {'animal_class': Okapi}], class_name_func=get_class_name)

class AnimalTests(TestCase):

def test_speak(self):

sound = self.animal_class().speak()

self.assertIsInstance(sound, str)

self.assertGreater(len(sound), 0)

```

  • 단점
  • IDE 지원 부족
  • class_name_func 커스터마이징 필요

결론

  • 테스트 코드는 가독성과 디버깅 편의성을 위해 pytest.mark.parametrize와 같은 명시적 방법을 사용해야 한다
  • 테스트 상속 패턴은 유지보수성과 명확성 희생으로 비용이 더 크다
  • DRY 원칙은 테스트 코드에서는 가독성과 명확성보다 우선시 되어야 한다