-
5. 목과 테스트의 취약성개발 도서/Unit Testing 2024. 6. 17. 17:34
이전 장에서 언급했던 목과 테스트 취약성에 대해 알아본다.
5.1 목과 스텁 구분
목과 스텁은 테스트 대역의 유형이다.5.1.1 테스트 대역 유형
테스트 대역 유형에는 더미, 스텁, 스파이, 목, 페이크라는 총 다섯가지가 있다.
실제로는 목과 스텁 두가지로 구분되어 사용된다.두 유형의 차이는 아래와 같다.
- 목은 외부로 나가는 상호작용을 모방하고 검사하는데 도움이 된다. 이러한 상호 작용은 SUT가 상태를 변경하기 위한 의존성을 호출하는 것에 해당한다.(ex SMTP 서버)
- 스텁은 내부로 들어오는 상호 작용을 모방하는데 도움이 된다. 이러한 상호 작용은 SUT가 입력 데이터를 얻기 위한 의존성을 호출하는 것에 해당한다. (ex 데이터베이스)
5.1.2 도구로서의 목과 테스트 대역으로서의 목
목은 상황에 따라 다른 의미로 사용된다.
이전에 언급한 것과 같이 테스트 대역이라는 의미의 목이 존재하는 한편,
목 라이브러리의 클래스로도 목이라는 단어를 사용한다.
목 라이브러리를 통해 목을 생성하니 같은 의미가 아닌가 싶을 수 도 있지만, 목 뿐만이 아니라 스텁 등과 같은 테스트 대역 또한 생성할 수 있으니 상황에 맞는 해석이 필요하다.5.1.3 스텁으로 상호 작용을 검증하지 말라
스텁은 내부 상호 작용을 모방하며, 그 결과는 최종 결과와 일치하지 않는다.
4장에서 언급한 내용과 같이 구현 세부 사항을 검증하면 리팩토링 내성이 깨지게 된다.
이는 스텁으로 상호 작용을 검증하면 안된다는 뜻과 같다.5.1.4 목과 스텁 함께 쓰기
때로는 목과 스텁의 영역에 둘다 걸치는 테스트 대역을 만들어야 할 때도 있다.
예를들면 SUT의 동작이 스텁으로 생성한 클래스의 메서드를 실행시키고 그것을 검증하게 될 때, 이는 목이면서 스텁이기도 하다.
하지만 목이라는 사실이 스텁보다 중요하기에 대체로 목이라고 부른다.5.1.5목과 스텁은 명령와 조회에 어떻게 관련돼 있는가?
명령 조회 분리(SQS) 원칙에 따르면, 모든 메서드가 명령 또는 조회 중 하나여야 하지만 둘 다는 안된다. 명령을 대체하는 테스트 대역은 목이다. 조회를 대체하는 테스트 대역은 스텁이다.5.2 식별할 수 있는 동작과 구현 세부 사항
5.2.1 식별할 수 있는 동작은 공개 API와 다르다
모든 제품 코드는 2차원으로 분류할 수 있다.- 공개 API 또는 비공개 API
- 식별할 수 있는 동작 또는 구현 세부 사항
코드의 공개성은 private, public, internal등 접근 제어자에 의해 제어된다.
다음 요구사항을 하나라도 충족하면 식별할 수 있는 동작이다.- 클라이언트가 목표를 달성하는 데 도움이 되는 연산을 노출하라. 연산은 계산을 수행하거나 사이드 이펙트를 초래하거나 또는 둘 다 하는 메서드이다.
- 클라이언트가 목표를 달성하는 데 도움이 되는 상태를 노출하라. 상태는 시스템의 현재다.
5.2.3 잘 설계된 API와 캡슐화
잘 설계된 코드는 식별할 수 있는 동작이 공개 API와 일치하고, 구현 세부 사항이 비공개 API 뒤에 숨겨져 있는 코드다. 공개 API가 식별할 수 있는 동작 이상으로 커지면 코드는 구현 세부 사항을 유출한다.캡슐화는 코드를 불변셩 위반으로부터 보호하는 행위다. 클라이언트는 구현 세부 사항을 사용해 코드의 불변성을 우회할 수 있기 때문에 구현 세부 사항을 노출하면 캡슐화가 위반되는 경우가 종종 있다.
5.3 목과 테스트 취약성 간의 관계
5.3.1 육각형 아키텍처 정의
육각형 아키텍처는 상호 작용하는 애플리케이션의 집합이고, 각 애플리케이션은 육각형으로 표시된다.
각 육각형은 도메인과 애플리케이션 서비스라는 두 계층으로 분리된다.MVC패턴에서 Model과 Controller의 관계와 동일한 것으로 보여 자세한 설명은 생략한다.
5.3.2 시스템 내부 통신과 시스템 간 통신
시스템 내부 통신 : 애플리케이션 내 클래스 간의 통신
시스템 간 통신 : 다른 애플리케이션과의 통신5.3.3 시스템 내부 통신과 시스템 간 통신의 예
시스템 내 통신은 세부 구현 사항이다.
애플리케이션을 통해서만 접근할 수 있는 외부 시스템을 제외하고 시스템 간 통신은 식별할 수 있는 동작이다.
애플리케이션을 통해서만 접근할 수 있는 외부 시스템과의 상호 작용도 구현 세부 사항인데, 그 결과의 사이트 이펙트를 외부에서 확인할 수 없기 때문이다.5.4 단위 테스트의 고전파와 런던파 재고
런던파를 따라 목을 무분별하게 사용하면 종종 구현 세부 사항에 결합돼 테스트에 리팩터링 내성이 없게 된다.
고전파는 테스트 간에 공유하는 의존성만 교체하자고 주장하므로, 이 문제에 대해서 유리하다.
하지만 고전파 역시 시스템 간 통신에 대한 처리에 이상적이지 않다.
고전파도 목 사용을 지나치게 장려한다.5.4.1 모든 프로세스 외부 의존성을 목으로 해야 하는 것은 아니다
시스템 내 통신을 검증하고자 목을 사용하면 취약한 테스트로 이어진다.
따라서 시스템 간 통신과 해당 통신의 사이드 이펙트가 외부 환경에서 보일 때만 목을 사용하는 것이 타당하다.이 장을 읽기 전에 작성한 테스트에서, 특히 Repository객체들을 Mock으로 대체하며 위와 같은 문제점에 맞이한 적이 있다. 다만 실제 DB를 사용했을 때의 부담을 생각하면, h2와 같은 테스트 용도의 DB를 사용하여 실제 코드를 활용하는게 좋다는 것이 현재의 내 결론이다.
'개발 도서 > Unit Testing' 카테고리의 다른 글
7. 가치 있는 단위 테스트를 위한 리팩터링 (0) 2024.06.20 6. 단위 테스트 스타일 (0) 2024.06.18 4. 좋은 단위 테스트의 4대 요소 (0) 2024.06.14 3. 단위 테스트 구조 (0) 2024.06.04 2. 단위 테스트란 무엇인가 (0) 2024.06.03