5장. 목과 테스트 취약성

5장. 목과 테스트 취약성

런던파는 테스트 대상 코드 조각을 서로 분리하고 불변 의존성을 제외한 모든 의존성에 테스트 대역을 써서 격리하고자 한다

고전파는 단위 테스트를 분리해서 병렬로 실행할 수 있게 하자고 한다 테스트 간에 공유하는 의존성에 대해서만 테스트 대역을 사용한다

목과 스텁 구분

테스트 대역의 종류

  • 목(mock)
  • 스텁(stub)
  • 가짜(fakes)
  • 스파이(spy)
  • 더미(dummy)

테스트 대역 유형

테스트 대역은 모든 유형의 비운영용 가짜 의존성을 설명하는 포괄적인 용어다

  • 목은 외부로 나가는 상호 작용을 모방하고 검사하는데 도움이 된다
  • 스텁은 내부로 들어오는 상호 작용을 모방하는데 도움이 된다

도구로서의 목과 테스트 대역으로서의 목

도구로써 목은 목라이브러리의 클래스도 목으로 참고할 수 있다

스텁으로 상호 작용을 검증하지 말라

스텁과의 상호 작용을 검증하는 것은 취약한 테스트를 야기하는 일반적인 안티 패턴이다

최종 결과가 아닌 사항을 검증하는 이러한 관행을 과잉 명세라고 부른다

목을 쓰면 무조건 테스트 취약성을 초래하는 것은 아니지만 대다수 그렇다

목과 스텁 함께 쓰기

때로는 목과 스텁의 특성을 모두 나타내는 테스트 대역을 만들 필요가 있다

목과 스텁은 명령과 조회에 어떻게 관련돼 있는가

목과 스텁의 개념은 명령 조회 분리 원칙과 관련이 있다

CQS 원칙에 따르면 모든 메서드는 명령이거나 조회여야 하고 이 둘을 혼용해서는 안된다

명령은 부작용을 일으키고 어떤 값도 반환 하지 않는다

식별할 수 있는 동작과 구현 세부 사항

단위 테스트에서 리패터링 내성 지표가 가장 중요하다

테스트는 어떻게가 아니라 무엇에 중점을 뒤야한다

식별할 수 있는 동작은 공개 API와 다르다

모든 제품 코드는 2차원으로 분류 가능

  • 공개 API 또는 비공개 API
  • 식별할 수 있는 동작 또는 구현 세부 사항

각 차원의 범주는 겹치지 않는다

코드가 시스템의 식별할 수 있는 동작이려면 다음중 하나를 해야 한다

  • 클라이언트가 목표를 달성하는 데 도움이 되는 연산을 노출하라
  • 클라이언트가 목표를 달성하는 데 도움이 되는 상태를 노출하라

잘 설계된 API와 캡슐화

장기적으로 코드베이스 유지 보수에서는 캡슐화가 중요하다. 복잡도 때문이다

  • 구현 세부 사항을 숨기면 클라이언트의 시야에서 클래스 내부를 가릴 수 있기 때문에 내부를 손상시킬 위험이 적다
  • 데이터와 연산을 결합하면 해당 연산이 클래스의 불변성을 위반하지 않도록 할 수 있다

구현 세부 사항 유출: 상태의 예

API를 잘 설계하면 단위 테스트도 자동으로 좋아진다

클라이언트가 목표를 달성하는 데 직접적으로 도움이 되는 코드만 공개해야 하며 다른 모든 것은 구현 세부 사항이므로 비공개 API뒤에 숨어 있어야 된다

목과 테스트 취약성 간의 관계

육각형 아키텍처 정의

도메인과 애플리케이션 서비스라는 두 계층으로 나눈다
애플리케이션 서비스 계층과 도메인 계층의 조합은 육각형을 형성하며 이 육각형은 애플리케이션을 나타낸다

  • 도메인 계층과 애플리케이션 서비스 계층 간의 관심사의 분리
  • 애플리케이션 내부 통신
  • 애플리케이션 간의 통신

시스템 내부 통신과 시스템 간 통신

시스템 내부 통신은 구현 세부 사항이고 시스템 간 통신은 그렇지 않다

시스템 간 통신의 특성은 별도 애플리케이션과 함께 성장하는 방식에서 비롯된다
성장의 주요 원칙중 하나라 하위 호환성을 지키는 것이다

단위 테스트의 고전파와 런던파 재고

런던파는 불변 의존성을 제외한 모든 의존성에 목 사용을 권장하며 시스템 내 통신과 시스템 간 통신을 구분하지 않는다

고전파는 테스트 간에 공유하는 의존성만 교체하자고 한다

모든 프로세스 외부 의존성을 목으로 해야 하는 것은 아니다

  • 공유 의존성
  • 프로세스 외부 의존성
  • 비공개 의존성

고전파는 공유 의존성을 피할 것을 권고 한다

목을 사용한 동작 검증

종종 목이 동작을 검증한다고 한다 하지만 대부분의 경우는 그렇지 않다

참조