들어가며
단위 테스트와 기반 코드를 서로 얽혀있다. 따라서 코드 베이스에 노력을 기울이지 않고서는 가치 있는 테스트를 만들 수 없다. 이번 장에서는 코드의 네 가지 유형을 살펴보고 어떤 유형이 테스트하기 적합한지 알아보자.
코드의 네 가지 유형
모든 제품 코드는 2차원으로 분류할 수 있다.
- 복잡도 또는 도메인 유의성
- 코드의 복잡도는 코드 내 의사 결정(분기) 지점 수로 정의한다. 이 숫자가 클수록 복잡도는 더 높아진다.
- 도메인 유의성은 코드가 프로젝트의 문제 도메인에 대해 얼마나 의미 있는지를 나타낸다. 일반적으로 도메인 계층의 모든 코드는 최종 사용자의 목표와 직접적인 연관성이 있으므로 도메인 유의성이 높다.
- 협력자 수
- 협력자는 가변 의존성이거나 프로세스 외부 의존성이다.
- 협력자가 많은 코드는 테스트 비용이 많이 든다. 상호 작용 확인을 위한 코드(의존 객체 세팅, 목 등)가 필요하기 때문이다.
코드 복잡도/도메인 유의성과 협력자를 고려하면 제품 코드를 네 가지로 구분할 수 있다.
- 도메인 모델과 알고리즘
- 보통 복잡한 모델은 도메인 모델이다. 그러나 문제 도메인과 직접적으로 관련이 없는 복잡한 알고리즘이 있는 경우가 있다.
- 단위 테스트에 가장 적합한 유형이다.
- 간단한 코드
- getter, setter와 같은 단순한 로직이나 매개 변수가 없는 생성자 등이 해당된다.
- 테스트할 필요가 없다.
- 컨트롤러
- 여기서는 복잡하거나 비즈니스에 중요한 작업을 하지 않는다. 도메인 클래스와 외부 애플리케이션 같은 다른 구성 요소의 작업을 조정하는 역할만 수행한다.
- application 영역에 해당되며, 통합 테스트에 적합하다.
- 지나치게 복잡한 코드
- 덩치가 큰 서비스 로직과 같이, 협력자가 많으며 복잡하거나 중요하다.
- 협력자가 많아 단위 테스트가 어렵기 때문에 도메인 모델/알고리즘과 컨트롤러라는 두 부분으로 나누어야 한다.
컨트롤러(application 서비스)에서 조건부 로직 처리
비즈니스 로직과 오케스트레이션의 분리는 다음과 같이 비즈니스 연산이 세 단계로 있을 때 가장 효과적이다.
- db에서 데이터 조회
- 비즈니스 로직 실행
- db에 데이터 저장
하지만 비즈니스 로직 중간에 외부에서 추가 데이터를 조회하는 등의 작업이 있다면 어떻게 할까? 크게 세 가지 방법이 있다.
- 외부에 대한 모든 읽기와 쓰기를 비즈니스 연산 가장자리로 밀어내기 : 컨트롤러 단순화를 유지하고 프로세스 외부 의존성과 도메인 모델을 분리할 수 있다. 하지만 필요 없는 경우에도 외부 의존성을 호출하기 때문에 성능이 저하된다.
- 도메인 모델에 프로세스 외부 의존성을 주입하기 : 성능을 유지하면서 컨트롤러를 단순화할 수 있다. 하지만 도메인 모델의 테스트 유의성이 떨어진다.
- 의사 결정 프로세스 단계를 더 세분화 하기 : 성능과 도메인 모델 테스트 유의성에 도움을 준다. 하지만 컨트롤러에 의사 결정 지점이 생기므로 복잡해진다.
대부분의 소프트웨어 프로젝트는 성능이 매우 중요하다. 도메인 모델에 외부 의존성을 주입하면 테스트와 유지보수가 어려워진다. 따라서 의사 결정 프로세스 단계를 더 세분화하는 방법만 남는다. 컨트롤러가 복잡해지긴 하지만 이를 완화하는 방법이 있다.
컨트롤러 복잡도를 완화하는 방법
- canExecute/execute 패턴 사용 : 복잡한 코드를 최대한 도메인 모델에 집어 넣고, 애플리케이션 서비스에서는 canExecute가 true일 때만 실행하도록 단순화 할 수 있다.
- 도메인 이벤트 사용 : 비즈니스 로직 중간에 외부 시스템에 알려야 하는 상황이 있을 수 있다. 도메인 이벤트를 사용하면 비즈니스 로직에서는 그저 이벤트를 던지기만 하고, 애플리케이션 서비스에서 일괄적으로 처리하도록 할 수 있다. 자세한 내용은 다른 페이지에서 다루도록 하겠다.
개인적인 견해로 코틀린에서는 파라미터로 함수를 넘기는게 가능하기 때문에, 해당 방법을 사용하면 외부 의존성과 의사 결정이 효과적으로 분리가 가능하다고 생각한다.
'테스트' 카테고리의 다른 글
목 사용 팁 (0) | 2023.09.18 |
---|---|
단위/통합 테스트에서의 데이터베이스 (0) | 2023.09.18 |
단위 테스트의 세 가지 스타일 (0) | 2023.09.17 |
테스트 대역(Test Double)이란? (0) | 2023.09.17 |
좋은 단위 테스트의 4대 요소 (0) | 2023.09.17 |