우아한 테크캠프 PRO 3기 - 인수 테스트 주도 개발
이번 주차 강의에서는 ATDD(인수 테스트 주도 개발)에 대해 학습했습니다. TDD는 아래와 같이 테스트 코드 작성 > 리팩터링 > 테스트 코드 수정의 사이클로 이루어 집니다.
인수테스트란?
그런데 테스트 코드를 작성하기 위해서는 해당 도메인에 대한 지식이 요구되는데, 이해가 부족하다면 테스트 코드 작성에 어려움이 있습니다. 이 경우 ATDD를 사용해 테스트 주도 개발을 진행할 수 있습니다.
프로그램을 인수할 때는 인수조건을 만족해야하며, 인수 조건은 인수 테스트가 충족해야하는 조건입니다. 즉, 인수테스트가 통과되면, 그 프로그램의 기능 구현은 끝이며 프로그램을 인수할 수 있다고 볼 수 있습니다.
인수테스트를 통해 리팩터링을 하는 방법은 다음과 같습니다.
- 먼저 인수 테스트를 작성하여 기존에 구현된 기능을 보호하기
- 파악이 가능한 부분부터 단위 테스트를 만들어 기능 검증하기
인수테스트 도구
@SpringBootTest
- SpringBootTest는 실제 애플리케이션을 자신의 로컬 위에 올려서 포트 주소가 Listening 되어지고, 실제 Database와 커넥션이 붙어지는 상태에서 진행되는 Live 테스트 방법
- webEnvironment 설정을 통해 웹 서버의 환경을 지정
- MOCK : WebApplicationContext를 제공하고 가짜 서블릿 환경을 제공함. 내장된 서블릿 컨테이너를 사용하지 않음. 서블릿 API들이 클래스패스에 없으면 ApplicationContext 를 생성함. MOCK 설정은 MockMvc 기반의 어플리케이션 테스트를 위해 @AutoConfigureMockMvc 의 주입과 함께 사용되어 진다.
- RANDOM_PORT : ServletWebServerApplicationContext 을 로드하고 진짜 서블릿 환경을 제공함. 내장된 서블릿 컨테이너를 구동하고 random port로 리스닝 한다.
- DEFINED_PORT : ServletWebServerApplicationContext 을 로드하고 진짜 서블릿 환경을 제공함. 내장된 서블릿 컨테이너를 구동하고 설정된 port로 리스닝 한다. (application.properties 에 설정된 값 또는 8080 기본값)
- NONE : SpringApplication 을 사용하면서 ApplicationContext 이 로드된다. 그러나 서블릿 환경은 제공되지 않는다.
- SpringApplication에서 사용하는 ApplicationContext를 생성해서 작동
인수 테스트 객체 설정
- 테스트를 위한 서버에 요청을 보내기 위한 클라이언트 객체 설정
- ex. MockMvc, RestAssured, WebTestClient
- SpringApplication에서 사용하는 ApplicationContext를 생성해서 작동
MockMvc vs WebTestClient vs RestAssured
- MockMvc는 @SpringBootTest의 webEnvironment.MOCK과 함께 사용 가능하며 mocking 된 web environment(ex tomcat) 환경에서 테스트
- WebTestClient는 @SpringBootTest의 webEnvironment.RANDOM_PORT 나 DEFINED_PORT와 함께 사용, Netty를 기본으로 사용
- RestAssured는 실제 web environment(Apache Tomcat)을 사용하여 테스트
1단계 : 지하철 노선 관리
https://github.com/next-step/atdd-subway-admin/pull/369
1) @Transactional 사용
- Service, Repository에 @Transactional(readOnly = true)를 설정하면, Reader DB로 호출된다.
- 단, Repository에 @Transactional(readOnly = true)가 있어도 상위 호출자인 Service에서 @Transactional로 되어있다면 MasterDB를 호출한다.
- 이는 @Transactional의 기본 propagation이 REQURIES이기 때문이다.
- Repository의 propagation을 REQUIRES_NEW로 지정하면 ReadOnly 트랜잭션이 신규 생성되어 ReaderDB로 호출이 전달된다.
- 단, 이럴 경우 DirtyChecking이 안되기 때문에 DirtyChecking이 필요한 Entity 조회시에는 Service의 트랜잭션을 사용한다.
2) Exception 관리
2단계 : 인수테스트 리팩터링
https://github.com/next-step/atdd-subway-admin/pull/381
3단계 : 구간 추가 기능
https://github.com/next-step/atdd-subway-admin/pull/396
4단계 : 구간제거기능
https://github.com/next-step/atdd-subway-admin/pull/415
댓글남기기