아키텍처 요소 테스트
Last updated
Last updated
만드는 비용이 적고 유지보수하기 쉽고 빨리 실행되고 안정적인 작은 크기의 테스트들에 대해 높은 커버리지를 유지하는 것이 중요하다.
테스트가 비싸질수록 테스트의 커버리지 목표는 낮게 잡아야 시간을 덜 쓸 수 있다.
단위테스트
피라미드의 토대, 하나의 클래스를 인스턴스화하고 클래스의 인터페이스를 통해 기능을 테스트
다른 클래스에 의존하면 인스턴스화 대신 mock으로 대체한다
통합테스트
연결된 여러 유닛을 인스턴스화하고 시작점이 되는 클래스의 인터페이스로 데이터 보낸 후 유닛들이 잘 동작하는지 검증
시스템 테스트
애플리케이션을 구성하는 모든 객체 네트워크를 가동해 특정 유스케이스가 전 계층에서 동작하는지 검증
UI를 포함하는 end-to-end 테스트층이 있을 수 있다.
단위테스트를 사용해 간단하게 테스트할 수 있다.
비즈니스 규칙을 검증하기에 적절하다.
도메인 엔티티의 행동은 다른 클래스에 거의 의존하지 않아 단위 테스트 말고 다른 종류의 테스트는 필요하지 않다.
단위테스트이긴 하지만 의존성의 상호작용을 테스트하므로 통합테스트라는 의미에 가깝지만 실제 의존성 관리를 하지 않으므로 완전한 통합테스트는 아님
행동-주도 개발(behavior driven develpment)에서 일반적으로 사용되는 방식대로 given/when/then
으로 나눈다.
Mockito를 사용해 목 객체를 생성하고 메서드 행동을 정의할 수 있다.
테스트 중인 서비스는 상태가 없어 then
에서 특정 상태를 검증할 수 없다.
서비스가 의존 대상의 특정 메서드와 상호작용했는지 여부를 테스트하는것이 목적
테스트가 코드의 행동 변경뿐만 아니라 구조 변경에도 취약해지므로 모든 동작을 검증하는 대신 핵심만 골라 테스트하는 것이 좋다.
모든 동작을 검증하려하면 클래스가 조금 바뀌어도 테스트를 변경해야 하므로 테스트의 가치가 떨어진다.
@MockMvcTest
를 사용해 웹 컨트롤러 테스트하는 방법을 사용한다.
위 어노테이션을 사용하면 스프링이 특정 요청 경로, 자바와 JSON 매핑, HTTP 입력 검증에 필요한 전체 객체 네트워크를 인스턴스화하므로 통합 테스트이다.
JSON 문자열 등의 형태로 HTTP를 통해 입력받고 → 유효성 검증하고 → 유스케이스 포맷으로 매핑하고 → 유스케이스로 전달하는 과정을 테스트한다.
웹 컨트롤러는 스프링 프레임워크에 강하게 묶여있으므로 이 프레임워크와 통합된 상태로 테스트하는 것이 합리적이다.
단순 어댑터 로직 뿐만 아니라 데이터베이스 매핑도 검증하므로 통합 테스트를 적용한다.
@DataJpaTest
어노테이션으로 데이터베이스 접근에 필요한 객체 네트워크를 인스턴스화 해야한다는 것을 스프링에게 알려준다.
@Import
어노테이션을 추가해서 특정 객체가 이 네트워크에 추가됐다는 것을 표현한다.
@Sql("XXX.sql")
어노테이션을 사용해 데이터베이스를 특정 상태로 만들 수 있다.
데이터베이스를 모킹하지 않고 실제로 접근
실제 연동했을 때 SQL 구문의 오류나 테이블과 자바 객체 간의 매핑 에러로 문제 생길 확률이 높아진다.
따라서 프로덕션 환경에서는 실제 데이터베이스를 대상으로 테스트 진행해야 한다.
Testcontainers같은 라이브러리는 필요하느데이터베이스를 도커 컨테이너에 띄울 수 있어 유용
전체 애플리케이션을 띄우고 API를 통해 요청 보내고 모든 계층이 동작하는지 시스템 테스트를 진행
유스케이스의 시스템 테스트
@SpringBootTest
어노테이션 사용해 스프링이 애플리케이션을 구성하는 모든 객체 네트워크를 띄우고, webEnvironment = WebEnvironment.RANDOM_PORT
한다.
TestRestTemplate을 사용하면 실제 HTTP 통신을 통해 요청을 보낸다.
다른 시스템과 통신하는 애플리케이션의 경우 일부 출력 포트 인터페이스만 모킹하면 된다.
헬퍼 메서드를 사용해 여러 상태 검증 시 사용할 수 있는 Domain Specific Language 를 형성
사용자 관점에서 애플리케이션을 검증할 수 있다.
단위 테스트와 통합 테스트를 만들었다면 시스템 테스트는 앞서 커버한 코드와 겹치는 부분이 많지만, 단위/통합테스트로는 못잡는 계층간 매핑 버그 등을 찾아낼 수 있다.
여러 유스케이스를 결합해 시나리오를 만들어 시나리오들을 커버한다면 최신 변경 사항에도 애플리케이션이 망가지지 않았음을 보장할 수 있다.
라인 커버리지는 테스트 성공을 측정하는 데 있어서 잘못된 지표
테스트의 성공 기준은 얼마나 마음편하게 소프트웨어를 배포할 수 있는지이다.
자주 배포할수록 테스트를 더 신뢰할 수 있다.
프로덕션의 버그를 수정하고 이로부터 배우는 것을 우선순위로 하다보면 점점 방대한 케이스를 커버할 수 있는 테스트가 될 것