Featured image of post 28. 테스트 경계

28. 테스트 경계

5부 - 아키텍처

테스트는 시스템의 일부이며, 아키텍처에도 관여한다.

시스템 컴포넌트인 테스트

아키텍처 관점에서는 어떠한 종류에 테스트이든 동일하다.

테스트는 태생적으로 의존성 규칙을 따른다.

  • 테스트는 세부적이며 구체적이다.
  • 따라서 의존성은 항상 테스트 대상이 되는 코드를 향한다.(아키텍처의 가장 바깥쪽 원으로 볼 수 있다.)
  • 시스템 내부의 어떤 것도 테스트에는 의존하지 않는다.
  • 독립적으로 배포 가능하다.
  • 시스템 컴포넌트 중에서 가장 고립되어 있다.
  • 시스템 운영에 꼭 필요치는 않다.
  • 테스트의 역할은 운영이 아니라 개발을 지원하는 것이므로, 어떤 사용자도 테스트에 의존하지 않는다.

그렇다고 하더라도 테스트가 시스템 컴포넌트가 아니라는 뜻은 아니며, 다른 모든 시스템 컴포넌트가 반드시 지켜야하는 모델을 표현해준다.

테스트를 고려한 설계

테스트의 극단적인 고립성이 대체로 배포하지 않는다는 사실과 어우러져, 테스트가 시스템의 설계 범위 밖에 있다고 착각한다.

테스트가 시스템 설계와 잘 통합되지 않으면, 테스트는 깨지기 쉬워지고, 시스템은 뻣뻣해져서 변경하기가 어려워진다.

깨지기 쉬운 테스트 문제(Fragile Tests Problem)

시스템에 강하게 결합된 테스트라면 시스템이 변경될 때 함께 변경되어야하므로, 시스템 컴포넌트에 생긴 아주 사소한 변경도, 이와 결합된 수많은 테스트를 망가뜨릴 수 있다.

시스템의 공통 컴포넌트가 변경되면 수백, 심지어 수천 개의 테스트가 망가진다.


깨지기 쉬운 테스트는 시스템을 뻣뻣하게 만든다는 부작용을 낳을 때가 많다.

  • 시스템에 가한 간단한 변경이 대량의 테스트 실패로 이어진다는 사실을 알게되면, 개발자는 변경을 하지 않으려고 할 것이다.

따라서 이러한 문제를 해결하기 위해 테스트를 고려한 설계가 필요하다.

핵심은 변동성이 있는 것에 의존하지 않는 것이다.

변동성이 큰 GUI같은 것으로 시스템을 조작하는 테스트 스위트는 깨지기 쉽기 때문에 시스템과 테스트를 설계할 때 GUI를 사용하지 않고 업무 규칙을 테스트 할 수 있게 해야한다.

테스트 API

변동성이 적은 방식으로 업무 규칙을 테스트하기 위해 모든 업무 규칙을 검증하는 데 사용할 수 있도록 특화된 API를 만든다.

  • 보안 제약 사항을 무시할 수 있어야 한다.
  • 데이터베이스와 같은 값비싼 자원은 건너뛰고, 시스템을 테스트 가능한 특정 상태로 강제하는 강력한 힘을 지녀야한다.
  • 사용자 인터페이스가 사용하는 인터렉터인터페이스 어댑터들의 상위 집합이 될 것이다.

테스트 API는 테스트를 애플리케이션으로부터 분리할 목적으로 사용한다.

구조적 결합

구조적 결합은 테스트 결합 중에서 가장 강하며, 가장 은밀하게 퍼져나가는 유형이다.

모든 상용 클래스에 테스트 클래스가 각각 존재하고, 모든 상용 메서드에 테스트 메서드 집합이 각각 존재하는 테스트 스위트가 있다고 가정할 때 이러한 테스트 스위트는 애플리케이션 구조에 강하게 결합되어있다.

  • 상용 클래스나 메서드 중 하나라도 변경되면 딸려있는 다수의 테스트가 변경되어야한다.
  • 테스트는 깨지기 위워지고, 이로 인해 상용 코드를 뻣뻣하게 만든다.

테스트 API의 역할은 애플리케이션의 구조를 테스트로부터 숨기는 데 있다.

  • 상용 코드를 리펙터링하거나 진화시키더라도 테스트에는 전혀 영향을 주지 않는다.
  • 테스트를 리펙터링 하거나 진화시킬 때도 사용 코드에는 영향을 주지 않는다.

시간이 지날수록 테스트는 계속해서 더 구체적이고 특화된 형태로 변하고, 상용 코드는 더 추상적이고 범용적인 형태로 변하기 때문에 따로따로 진화할 수 있다는 점은 필수적이다.

하지만 구조적 결합이 강하면 위와 같은 진화 과정을 방해한다.

보안

테스트 API를 운영 시스템에 배포하면 위험에 처할 수 있다.

테스트 API 자체와 테스트 API 중 위험한 부분의 구현부를 독립적으로 배포할 수 있는 컴포넌트로 분리해야한다.

결론

테스트는 시스템의 일부이다.

따라서 테스트에서 기대하는 안정성과 회귀의 이점을 얻을 수 있으려면 테스트는 잘 설계 돼야만한다.

테스트를 시스템의 일부로 설계하지 않으면 테스트는 깨지기 쉽고 유지보수하기 어려워지는 경향이 있으며, 이러한 테스트는 유지보수하기 힘들기 때문에 버려지는 최후를 맡는다.