-
7장 - 아키텍처 요소 테스트하기클린 코드(Clean Code)/만들면서 배우는 클린 아키텍처 요약 2023. 3. 1. 00:01
이번장에서는 육각형 아키텍처의 각 요소들을 테스트할 수 있는 테스트 유형에 대해 논의합니다.
단위 테스트로 도메인 엔티티 테스트하기
Account의 상태를 특정 시점의 계좌 잔고와 그 이후 입출금 내역으로 구성되어 있습니다.
withdraw() 메서드가 기대한 대로 동작하는지 검증하려면 단지 도메인 엔티티인 Account를 인스턴스화 하고 메서드를 호출하여 출금이 성공하는지 검증하고 객체의 상태에 기대되는 부수효과들이 잘 일어났는지 확인하는 단순한 단위 테스트를 수행할 수 있습니다.
도메인 엔티티는 다른 클래스에 거의 의존하지 않기 때문에 다른 종류의 테스트는 필요하지 않습니다.
단위 테스트로 유스케이스 테스트하기
테스트 가독성을 높이기 위해 given/when/then 섹션으로 나누어 작성하였습니다.
given에는 출금 및 입금 Account의 인스턴스를 각각 생성하고 적절한 상태로 만들어 given...()으로 시작하는 메서드의 인자로 넣습니다.
when 섹션에서는 유스케이스를 실행하기 위해 sendMoney() 메서드를 호출합니다.
then 섹션에서는 트랜잭션이 성공적이었는지 확인하지 출금 및 입금 Account, 계좌에 락을 걸고 해제하는 책임을 가진 accountLock에 대해 특정 메서드가 호출되었는지 검증합니다.
테스트를 할 때 Mockito 라이브러리를 이용해 목 객체를 만들고 특정 메서드가 호출되었는지 검증할 수 있습니다.
이때 주의할점은 테스트 코드가 행동 변경뿐만 아니라 코드의 구조 변경에도 취약해질 수 있습니다.
따라서 모든 동작을 검증하려고 하면 클래스가 조금만 바뀌어도 테스트가 변경됩니다.
이렇게 되면 테스트의 가치가 떨어지게 되며 중요한 핵심만 골라 집중해서 테스트하는 것이 좋습니다.
통합 테스트로 웹 어댑터 테스트하기
웹 어댑터는 json 문자열 등의 형태로 HTTP를 통해 입력을 받고, 입력에 대한 유효성 검증을 하고, 유스케이스에서 사용할 수 있는 포맷으로 매핑하고, 유스케이스에 전달하여 받은 결과는 json으로 매핑하고 HTTP 응답을 통해 클라이언트에게 반환합니다.
MockMvc 객체를 이용해 모킹하여 테스트하며 실제로 HTTP 프로토콜을 통해 테스트하진 않습니다.
하지만 입력을 JSON에서 Command 객체로 매핑하는 전 과정을 다룹니다.
이 테스트는 단위 테스트일까요? 통합테스트일까요?
하나의 웹 컨트롤러 클래스만 테스트한 것으로 보이지만, 사실 @WebMvcTest는 스프링이 특정 요청 경로, 자바와 JSON 간의 매핑, HTTP 입력 검증 등에 필요한 전체 객체 네트워크를 인스턴스화하도록 만듭니다.
웹 컨트롤러가 스프링에 강하게 묶여 있기 때문에 격리된 상태로 테스트하기보다는 이 프레임워크와 통합된 상태로 테스트하는 것이 합리적입니다.
이로써 모든 매핑, 유효성 검증, HTTP 항목에 대한 커버리지가 높아지게되며, 프로덕션 환경에서 정상적으로 동작함을 보장하게 됩니다.
통합 테스트로 영속성 어뎁터 테스트하기
@DataJpaTest를 활용하여 스프링 데이터 리포지토리를 포함하여 데이터베이스 접근에 필요한 객체 네트워크를 인스턴스화해야 한다고 스프링에 명시합니다.
@Import를 통해 특정 객체가 이 네트워크에 추가되었다는 것을 명확하게 표현할 수 있습니다.
이 테스트에서는 데이터베이스를 모킹하지 않았으며 테스트가 실제로 데이터베이스에 접근합니다.
스프링은 기본적으로 인메모리 데이터베이스를 테스트에 사용합니다.
따라서 실제 프로덕션 환경에서는 문제가 생길 가능성도 높습니다.(데이터베이스마다 고유한 SQL 문법)
이러한 이유로 Testcontainers 같은 라이브러리는 필요한 데이터베이스를 도커 컨테이너에 띄울 수 있기 때문에 이런 측면에서 아주 유용합니다.
시스템 테스트로 주요 경로 테스트하기
@SpringBootTest는 스프링 애플리케이션을 구성하는 모든 객체 네트워크를 띄우게 합니다.
시스템 테스트는 단위 테스트나 통합 테스트가 할 수 있는 것보다 훨씬 더 실제 사용자를 잘 흉내내기 때문에 사용자 관점에서 애플리케이션을 검증할 수 있도록 합니다.
또한 여러 개의 유스케이스를 결합하여 시나리오를 만들 때 더 빛이 납니다.
얼만큼의 테스트가 충분할까?
얼마나 마음 편하게 소프트웨어를 배포할 수 있느냐가 테스트의 성공 기준이라고 생각합니다.
테스트를 실행한 후 소프트웨어를 배포해도 될 만큼 테스트를 신뢰한다면 그것으로 된 것입니다.
처음 배포에는 믿음의 도약이 필요하며, 이후는 프로덕션의 버그를 수정하고 이로부터 추가 테스트를 작성하면 됩니다.
시간이 지날수록 더 견고한 테스트가 됩니다.
만약 새로운 필드를 추가할 때마다 테스트를 고치는데 한 시간을 써야 한다면 뭔가 잘못된 것입니다.
이는 개선되어야 합니다.
유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까요?
핵심 도메인 로직은 단위 테스트, 어댑터는 통합 테스트로 처리되는 전략을 사용할 수 있습니다.
포트는 뚜렷한 모킹 지점이 되며 실제 구현을 이용할지 모킹할지 선택할 수 있습니다.
모킹하는 것이 너무 버거워지거나 어떤 종류의 테스트를 써야 할지 모르겠다면 이는 경고 신호입니다.
이런 측면에서 테스트는 아키텍처의 문제에 대해 경고하고 유지보수 가능한 코드를 만들기 위한 올바른 길로 인도하는 카나리아의 역할을 수행합니다.
'클린 코드(Clean Code) > 만들면서 배우는 클린 아키텍처 요약' 카테고리의 다른 글
9장 - 애플리케이션 조립하기 (0) 2023.03.03 8장 - 경계 간 매핑하기 (0) 2023.03.02 6장 - 영속성 어댑터 구현하기 (0) 2023.02.26 5장 - 웹 어댑터 구현하기 (0) 2023.02.25 4장 - 유스케이스 구현하기 (0) 2023.02.24