이 장은 완벽히 이해를 못한 것같음.. 테스트에 대해 조금 더 공부하고 봐야하지 않을까. 테스트 API..?
시스템 컴포넌트인 테스트
- 테스트는 시스템의 일부이며, 아키텍처에도 관여한다.
테스트를 고려한 설계
- 테스트가 지닌 극단적인 고립성이 테스트는 대체로 배포하지 않는다는 사실과 어우러지며, 개발자는 종종 테스트가 시스템의 설계 범위 밖에 있다고 여긴다. 이 관점은 치명적이다.
- 테스트가 시스템의 설계와 잘 통합되지 않으면, 테스트는 깨지기 쉬워지고, 시스템은 뻣뻣해져서 변경하기가 어려워진다.
- 깨지기 쉬운 테스트는 시스템을 뻣뻣하게 만든다는 부작용을 낳을 때가 많다.
- 이 문제를 해결하려면 테스트를 고려해서 설계해야 한다.
- (테스트를 고려하든 아니면 다른 이유든) 소프트웨어 설계의 첫 번째 규칙은 언제나 같다. 변동성이 있는 것에 의존하지 말라.
- GUI는 변동성이 크기에 GUI 로 시스템을 조작하는 테스트 스위트는 분명 깨지기 쉽다.
테스트 API
- 이 목표를 달성하려면 테스트가 모든 업무 규칙을 검증하는 데 사용할 수 있도록 특화된 API를 만들면 된다.
- 이러한 API는 보안 제약사항을 무시할 수 있으며, (데이터베이스와 같은) 값비싼 자원은 건너뛰고, 시스템을 테스트 가능한 특정상태로 강제하는 강력한 힘을 지녀야만 한다.
- 테스트 API는 테스트를 애플리케이션으로부터 분리할 목적으로 사용한다. 단순히 테스트를 UI에서 분리하는 것만이 아닌, 테스트 구조를 애플리케이션 구조로부터 결합을 분리하는 게 목표다.
구조적 결합
- 구조적 결합은 테스트 결합 중에서 가장 강하며, 가장 은밀하게 퍼져 나가는 유형이다.
- 모든 상용 클래스에 테스트 클래스가 각각 존재하고, 또 모든 상용 메서드에 테스트 메서드 집합이 각각 존재하는 테스트 스위트가 있다고 가정해보자. 이러한 테스트 스위트는 애플리케이션 구조에 강하게 결합되어 있다.
- 상용 클래스나 메서드 중 하나라도 변경되면 딸려 있는 다수의 테스트가 변경되어야 한다. 결과적으로 테스트는 깨지기 쉬워지고, 이로 인해 상용 코드를 뻣뻣하게 만든다.
- 테스트 API의 역할은 애플리케이션의 구조를 테스트로부터 숨기는 데 있다. 이렇게 만들면 상용 코드를 리팩터링하거나 진화시키더라도 테스트에는 전혀 영향을 주지 않는다. 또한 테스트를 리팩터링하거나 진화시킬 때도 상용 코드에는 전혀 영향을 주지 않는다.
- 이처럼 따로따로 진화할 수 있다는 점은 필수적인데, 시간이 지날수록 테스트는 계속해서 더 구체적이고 더 특화된 형태로 변할 것이고, 반대로 상용 코드는 더 추상적이고 더 범용적인 형태로 변할 것이기 때문
- 하지만 구조적 결합이 강하면 필수적인 진화 과정을 방해할 뿐 아니라 상용 코드의 범용성과 유연성이 충분히 좋아지지 못하게 막는다.
보안
- 테스트 API 가 지닌 강력한 힘을 운영 시스템에 배포하면 위험에 처할 수 있다. 위험을 피하고 싶다면 테스트 API 자체와 테스트 API 중 위험한 부분의 구현부는 독립적으로 배포할 수 있는 컴포넌트로 분리해야 한다.
결론
- 테스트는 시스템 외부에 있지 않다. 오히려 시스템의 일부다. 따라서 테스트에서 기대하는 안정성과 회귀의 이점을 얻을 수 있으려면 테스트는 잘 설계 돼야만 한다.
- 테스트를 시스템의 일부로 설계하지 않으면 테스트는 깨지기 쉽고 유지보수하기 어려워지는 경향이 있다.
- 이러한 테스트는 유지보수 하기가 너무 힘들기 때문에 결국 버려지는 최후를 맞는다.