일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | ||||||
2 | 3 | 4 | 5 | 6 | 7 | 8 |
9 | 10 | 11 | 12 | 13 | 14 | 15 |
16 | 17 | 18 | 19 | 20 | 21 | 22 |
23 | 24 | 25 | 26 | 27 | 28 |
- 코틀린
- 도메인 주도 개발 시작하기
- 책스터디
- 함수형프로그래밍
- 유지보수
- 개발방법론
- 스터디
- Boot Legacy 차이점
- TDD
- 테스트
- 개발서적
- FP
- Java
- 클린아키텍처
- Spring
- GrokkingFunctionalProgramming
- 이펙티브코틀린
- DDD
- 객체지향의사실과오해
- 계층형아키텍처
- 아키텍처
- 만들면서배우는클린아키텍처
- web
- 테스트주도개발
- Kotlin
- 추상화 설계
- Thymeleaf
- 헥사고날아키텍처
- template
- 조영호
- Today
- Total
김동형수 개발기
만들면서 배우는 클린아키텍처 - 07 정리 본문
아키텍처 요소 테스트하기
헥사고날 아키텍처에서 테스트 전략에 대해 이야기한다. 아키텍처의 각 요소들을 테스트할 수 있는 유형에 대해 논의한다.
테스트 피라미드
테스트의 지향하는 방향
- 만드는 비용을 적게
- 유지보술르 쉽게
- 실행속도가 빨라야한다
- 작은 크기의 테스트들에 대해 높은 커버리지를 유지
테스트의 비용이 높아질 수록 커버리지의 목표를 낮게 잡아야한다.
1. 단위테스트는 피라미드의 토대에 해당한다. 하나의 클래스를 인스턴스화하고 클래스의 인터페이스를 통해 기능들을 테스트한다.
만일 의존되는 클래스가 있다면 테스트하는 동안 모킹해서 사용한다.
profile을 이용해서 구현체를 나눌 수 있는데, 이때 test profile일 경우 mocking하는 구현체를 작성하면 될 것 같다.
2. 통합테스트는 연결된 여러 유닛을 인스턴스화하고 시작점이 되는 클래스 인터페이스로 데이터를 보낸 후 네트워크가 정상동작하는 지 확인한다. 책에서는 두개의 계층을 걸쳐서 테스트할 수 있기 때문에 팔요애 따라 의존성있는 인스턴스를 모킹한다.
3. 시스템 테스트는 특정 유스케이스가 전 계층에서 정상동작하는지 확인한다.
단위 테스트로 도메인 엔티티 테스트하기
withdraw() 메서드를 호출해서 출금을 성공했는지 검증하고, Account 객체의 상태가 기대되는 결과값으로 되었는지 확인하는 단위 테스트다.
단위 테스트로 유스케이스 테스트하기
transactionSucceeds() 메서드를 이용한 테스트
SendMoneyCommand 인스턴스도 만들어서 유스케이스의 입력으로 사용
Account 객체의 메서드를 호출할때 AccountLock이 정성적으로 처리되었는지 확인
Mockito는 목 객체에 대해서 특정 메서드가 호출됐는지 검증할 수 있는 then()메서드를 제공한다.
transactionSucceeds() 메서드로 테스트 중인 유스케이스는 stateless기 때문에 'then'으로 검증할 수 없다.
대신 서비스가 의존 대상의 트성 메서드와 상호작용했는지 여부를 검증한다. 이는 테스트코드가 유스케이스의 행동 변경뿐만 아니라 코드의 구조 변경에도 영향이 있기 때문에 리팩터링되면 테스트코드도 변경될 확률이 높아진다.
핵심기능만 집중해서 테스트를 하는 것이 좋다. 모든 동작 검증(통합테스트)하려고 하면 클래스의 코드가 조금만 변경되어도 테스트코드를 변경해야한다. 이는 테스트의 가치를 떨어뜨린다.
transactionSucceeds() 메서드는 상호작용을 테스트하기 때문에 통합테스트와 가깝다. 하지만 의존되는 클래스를 모두 모킹하기 때문에 완전한 통합 테스트보다는 유지보수가 용이하다.
통합 테스트로 웹 어댑터 테스트하기
웹 어댑터 테스트할 흐름
- JSON 문자열 등 형태로 HTTP를 통해 입력을 받는다.
- 입력에 대한 유효성 검증
- 유스케이스에서 사용하는 포멧으로 컨버팅
- 유스케이스에 전달
- 유스케이스 결과값 반환
- 결과값 JSON으로 컨버팅 후 HTTP 응답
LIFIC에서 하고 있는 테스트는 의존성이 있는 클래스가 모킹이 되지 않은 모듈이 많기 때문에 계층간 의존성이 있다.
책을 보면서 적용시키려면 많은 공수가 들어갈 것 같다. 벌써 눈물이 앞을 가린다.
웹 컨트롤러가 스프링 프레임워크에 강하게 묶여 있기 때문에 격리된 상태로 테스트하기 보다는 프레임워크와 통합된 상태로 테스트 하는 것이 합리적이다.
평범한 단위테스트로 테스트로 한다면 커버리지가 떨어지기 때문에 프레임워크와 통합된 상태로 하는게 좋다.
모든게 다 이상적일 순 없다. 효율성 측면에서 봤을때 적당한 타협이 필요하다.
통합 테스트로 영속성 어댑터 테스트하기
이 테스트에서는 데이터베이스를 모킹하지 않았다.
모킹을 했다면 같은 코드에서 높은 커리어를 보여주지만, 데이터베이스를 연동했을 때 SQL 구문 오류나 테이블과 엔티티 매핑오류등은 확인할 수 없을것이다.
인메모리 데이터베이스를 지원하지만 데이터베이스 특화된 SQL도 있기 떄문에 문제가 될 수 있다.
테스트 컨테이너를 사용한다면 필요한 데이터베이스를 도커 컨테이너에 띄울 수 있기 때문에 유용하다.
시스템 테스트로 주요 경로 테스트하기
MovcMvc를 이용해 요청을 보내는 것이 아닌 TestRestTemplate을 이용해서 요청을 보낸다. 프로덕션 환경에 가깝게 하기 위해서 실제 HTTP 통신을 하는 것이다.
언제나 서드파티 시스템을 실행하여 테스트 할 수 없기 때문에 헥사고날 아키텍처에서 포트 분리를 잘 해놨다면 필요한 포트만 모킹해서 문제를 해결할 수 있다.
도메인 특화 언어(DSL)을 사용했는데 테스트에서 유용하지만 시스템 테스트에서 더욱 의미를 가진다.
실제 사용자 흉내를 잘 내기 때문에 사용자 관점에서 애플리케이션을 검증할 수 있다.
시스템 테스트는 단위테스트, 통합테스트에서 커버한 코드와 겹치는 부분이 많을 것이다. 그럼에도 그 외에 종류의 버그를 발견해서 수정할 수 있게 해준다. 그 예로는 들면 계층 간 매핑 버그가 있다.
시스템 테스트는 여러개의 유스케이스를 결합해서 테스트할때 진가를 발휘한다.
테스트를 통해서 중요한 시나리오가 커버된다면 변경사항들이 애플리케이션을 망가뜨리지 않고 배포할 준비가 된다고 확신할 수 있다.
얼만큼의 테스트가 충분할까?
테스트를 성공하고 배포를 하고나서 발생하는 버그를 수정하고 이로부터 배우는 것을 우선순위로 삼으면 방향성이 맞다고 저자는 말한다.
발생한 버그를 커버할 수 있도록 테스트코드를 수정하고 지속적으로 개선해나간다면 배포할 때 마음이 편안하게 해줄 것이다.
헥사고날 아키텍처의 테스트 전략
- 도메인 엔티티를 구현할 때는 단위 테스트
- 유스케이스를 구현할 때는 단위 테스트
- 어댑터를 구현할 때는 통합 테스트
- 사용자가 취할 수 있는 중요 애플리케이션 경로는 시스템 테스트
리팩터링할때마다 테스트코드가 변경되고 그 시간이 오래걸린다면 테스트로서의 가치를 잃는다.
유지보수 가능한 소프트웨어를 만드는 데 어떻게 도움이 될까?
헥사고날 아키텍처는 어댑터가 깔끔하게 분리되어있어서 도메인 로직은 단위 테스트, 어댑터는 통합 테스트로 명확하게 전략을 정의할 수 있다.
모킹이 필요한 지점은 포트이고 구현/모킹에 대한 선택은 상황에 따라서 할 수 있다.
인터페이스 분리 원칙을 지켜서 포트인터페이스를 구성했다면 모킹은 더 쉬워질 것이다.
특정 코드에 대해서 사용해야할 테스트의 종류를 정하기 어렵다면 경고 신호라고 저자는 말한다.
테스트는 아키텍처의 방향성을 잃지 않게하는 역할을 하고 있다고 볼 수 있다.
'책 스터디 > [완료] 만들면서 배우는 클린아키텍처' 카테고리의 다른 글
만들면서 배우는 클린 아키텍처 - 09 정리 (0) | 2022.04.17 |
---|---|
만들면서 배우는 클린 아키텍처 - 08 정리 (0) | 2022.04.15 |
만들면서 배우는 클린 아키텍처 - 06 정리 (0) | 2022.04.13 |
만들면서 배우는 클린 아키텍처 - 05 정리 (0) | 2022.04.12 |
만들면서 배우는 클린 아키텍처 - 04 정리 (0) | 2022.04.11 |