- Published on
Software Testing 7 | 테스트 하기 좋은 설계라...
- Authors
- Name
- 이건창
Introduction
책에서는 육각형 아키텍처를 활용해 테스트 가능한 설계를 설명하고 있어. 하지만 내 생각에는 육각형 아키텍처가 아니더라고 테스트 가능한 설계를 만드는 일이 충분하다고 봐. 그래서 육각형 아키텍처를 제외하고 테스트 가능한 설계 만 설명해볼게.
테스트 가능한 설계
테스트 케이스를 고려하거나 작성할 때 어려움을 느끼게 되면 어느순간부터 테스트를 수행하지 않게 돼. 그래서 설계에서부터 테스트 가능성을 고려할 필요가 있어.
테스트 가능성을 고려한다면 설계부터 구현까지 많은 리소스가 소모되겠지만 엉망인 코드를 관리하는 것보다 훨 씬 싸게 먹혀.
한 달 구현하고 일 년 운영한다는 생각만 해도 기간으로도 충분히 차이가 발생해.
설계에서 테스트 가능성을 높이려면 (1)저수준을 격리
하고, (2)의존성 주입
할 수 있는 방향으로 디자인 해야 해. 왜 그래야 하는지, 그러면 어떤 장점이 있는지 이야기 해볼게.
1. 아키텍처의 관심사 : 인프라 코드 분리
인프라스트럭처는 외부 의존성을 다루는 코드를 말해. 즉, 내가 작성한 코드가 아니라면 전부 인프라 코드야. (라이브러리 코드 정도로 이해하면 좋겠어.)
그 중 통상적으로 이야기 하는 인프라 코드는 (1)느리거나
(2)복잡한
성격을 가져.
인프라 코드와 비즈니스 로직이 섞게 돼면 책임이 커지고 테스트하기 어려워져. 그래서 명확한 책임 분리를 통해 테스트를 간단하게 작성 할 수 있게 돼.
사용자 정보를 저장한다라는 행위를 설계한다면 다음처럼 변경 할 수 있어.

우린 사용자를 저장할 때 검증해야 할 행위들을 쉽게 테스트 할 수 있지.
변경 전과 변경 후의 테스트 케이스를 고려해볼게.
AS-IS
- 동일한 이메일이 있는지 확인하기 위해 얻은 커넥션을 검증한다.
- 동일한 이메일이 있는지 확인하기 위해 얻었던 커넥션이 해제되는지 검증한다.
- 사용자를 저장하기 위해 얻은 커넥션을 검증한다.
- 사용자를 저장하기 위해 얻었던 커넥션이 해제되는지 검증한다.
- 동일한 이메일이 없는 경우 사용자를 저장한다.
- 동일한 이메일이 있는 경우
IllegalArgumentException
예외가 발생한다.
TO-BE
- 동일한 이메일이 없는 경우 사용자를 저장한다.
- 동일한 이메일이 있는 경우
IllegalArgumentException
예외가 발생한다.
자바에서 제공해주는 커넥션 획득 해제하는 부분들은 테스트하지 않아도 되지. 우리는 검증하고 싶은 행위들만 쉽게 검증 할 수 있어.
2. 코드의 관심사 : 의존성과 제어
코드 수준에서 테스트 가능성을 높이기 위해서는 클래스 간 의존성 제어가 가능해야 해.
작성한 클래스를 테스트하려면 의존성을 테스트 할 수 있도록 제어할 수 있어야 해. 테스트 더블에서 이야기 했던 것 처럼 말이야.

의존성을 제어 할 수 있게 되면 테스트 생산성이 높아지고 관심사를 쉽게 관리 할 수 있어.
테스트가 주는 피드백
테스트가 어렵다.
는 생각이 든다면 테스트 하려는 대상의 책임이 너무 많다는 의미야. 이러한 테스트가 주는 피드백을 통해 구현 코드를 리팩토링하면서 테스트 가능성을 높일 수도 있어.
테스트 가능성
책에서는 다음과 같은 세 가지가 테스트를 해야하는지를 고민하고 있었어.
- private 메서드
- 정적 메서드
- 싱글턴 메서드
private 메서드
private 메서드인 경우 책임을 분리하기 위해서 만들어진 메서드가 아닌지 고민해야 해. 만약 책임을 분리하기 위한 메서드라면 의존성 레이어를 한 계층 더 추상화 해야 해.
정적 메서드
정적 메서드는 테스트 악영향을 미칠 수 있어. 이럴 경우 추상화를 통해 테스트 가능성을 높이는게 중요해. 예를 들어 LocalDateTime.now() 인 경우 Clock 클래스로 추상화 계층을 둔 것 처럼 말이야.
싱글턴 메서드
싱글톤 패턴도 테스트 악영향 미치는 데 한 몫 해. 싱글톤 객체는 교체 할 수 있도록 추상화해서 관리해야 해.
아키텍처에서 고민 할 일과 코드에서 고민 할 일
인프라 코드 분리는 보통 아키텍처 수준에서 고민하는 영역이야. 코드 영역에서 고민하는 의존성 관리 방법이지.
헥사고날에서 포트와 어댑터
데이터만 해도 데이터 사용이 유효한지, 일관성이 맞는지를 지속적으로 파악해야 하는 책임이 있어. 그럼 비즈니스 로직이 너무 비대해지는데, 포트와 어댑터 구성을 통해 비즈니스 로직에 집중해서 구현 할 수 있어.
그림은 기능과 포트 간의 관계로 분리했어.

즉, 외부 인프라와 관련된 로직을 어댑터에 관리하고 기능에서 필요한 함수들을 포트에서 가져오는 방법이야.
위처럼 분리하게 되면 고수준부터 집중 할 수 있어. 그럼 저수준의 의존하지 않고 outside-in 방식으로 개발할 수 있지.