1단계 방탈출 예약 관리 미션의 제공된 테스트 코드를 보면,
클래스단에 @SpringBootTest가 붙여져 있고 RestAssured 라이브러리를 통해 테스트 코드를 작성하고 있습니다.
오늘은 테스트 포트를 변경하려다 삽질을 해본 이야기에 대해 작성해보겠습니다.
👀 @SpringBootTest란
Spring Boot에서 Spring Boot 기능이 필요할 때 표준 스프링 테스트 @ContextConfiguration 어노테이션의 대안으로 사용할 수 있는 어노테이션입니다.
이 어노테이션은 Spring을 통해 테스트에 사용되는 ApplicationContext를 생성하는 방식으로 작동합니다.
다시 말해 스프링 테스트를 위해 ApplicationContext를 생성합니다.
🤔 webEnvironment 속성값
@SpringBootTest으로 webEnvironment을 설정할 수 있는데요. 옵션은 4가지입니다.
- MOCK(디폴트 설정)
- WebApplicationContext를 로드하고 Mock 웹 환경을 제공
- 즉, 이 모드에서는 실제 내장 서버는 실행X
(→ 실제 서버 실행 유무에 따른 차이는 다루지 않겠습니다)
- 즉, 이 모드에서는 실제 내장 서버는 실행X
- WebApplicationContext를 로드하고 Mock 웹 환경을 제공
- RANDOM_PORT
- WebServerApplicationContext를 로드하고 실제 웹 환경을 제공
- 실제 내장 서버를 실행
- Random하게 지정된 포트를 사용
- DEFINED_PORT
- WebServerApplicationContext를 로드하고 실제 웹 환경을 제공
- 실제 내장 서버를 실행
- application.properties에서 정의된 포트 또는 기본 포트인 8080를 사용
- NONE
- ApplicationContext를 로드하지만 WebEnvironment를 제공X
❌ 문제점
application이 실행 중인 상태라고 합시다.위 application은 스프링 기본 포트인 8080에서 실행 중인 것을 확인할 수 있습니다.
서버가 실행 중인 상태에서 테스트를 실행한다면?
다시 우리의 테스트로 돌아와볼까요? 현재 사용 중인 속성값은 DEFINED_PORT인데요.
위에서 DEFINED_PORT는 실제 서버를 application.properties에서 정의된 포트 또는 기본 포트인 8080에서 실행한다는 것을 알 수 있었습니다.
우리는 application.properties에서 따로 정의하지 않았기 때문에 8080에서 실행이 될 것을 예상할 수 있습니다.
네. 예상처럼 8080에서 실행을 시도했네요.
하지만 이미 8080에서 애플리케이션을 실행 중이고 있었기 때문에 8080 포트 충돌이 일어나 서버 실행에 실패합니다.
친절하게도 8080 포트에서 실행 중인 프로그램을 종료하거나 방금 실행한 어플리케이션을 다른 포트로 지정해서 실행해봐라 라고 해주네요.
✅ 실행 중인 프로그램을 종료하지 않고도 테스트를 실행하는 법
저는 8080 포트에서 실행 중인 프로그램을 종료하지 않고도 테스트를 실행하고 싶습니다.
때문에 테스트 환경의 포트를 변경하는 방법을 선택하겠습니다.
테스트 서버의 포트를 변경하기 위해 @SpringBootTest의 webEnvironment의 속성값을 변경해보겠습니다.
DEFINED_PORT처럼 실제 서버를 실행하지만 다른 포트에서 실행시키는 RANDOM_PORT를 사용하면 되겠죠?
🔇 변경 후 테스트 실행(application 동시 실행 X)
RANDOM_PORT로 변경 후 일단 기존 서버를 실행 시키지 않고 테스트를 돌려보겠습니다.
이럴수가.
모든 테스트가 실패했습니다.
어떤 오류가 발생했는지 살펴볼까요? 오류는 Connection오류가 뜨네요.
일단 우리가 원했던 것처럼 8080포트가 아닌 49664라는 새로운 포트에서 테스트 환경의 서버가 실행된 것을 볼 수 있습니다.
왜 Connection 오류가 뜰까요?
요청에 로그를 찍어본 테스트가 있습니다.
역시나 랜덤하게 생성된 57485라는 포트에서 실행되었네요. 하지만 테스트는 8080 포트로 요청을 보냈습니다.
❓ RestAssured
현재 우리의 테스트는 RestAssured 라이브러리를 사용하고 있는데요. RestAssured의 문서를 보면
“By default REST assured assumes host localhost and port 8080 when doing a request.”
즉, 기본적으로 RestAssured는 요청을 localhost:8080으로 보내게 되어있습니다.
때문에 현재 우리의 독립적인 테스트 환경을 위해 아무리 랜덤한 포트로 변경해도, 이 바보 테스트는 자기를 위해 실행 중인 57485 포트를 모르고 디폴트인 8080으로 계속 요청을 보내게 되는 거죠.
이 RestAssured 테스트에게 57485라는 포트 번호를 알려주어야 합니다.
😅 RANDOM_PORT 다시 보기
RestAssured 테스트에게 임의로 생성된 포트 번호를 알려주기 위해서는 임의로 생성된 포트 번호가 무엇인지 알아야겠죠?
우리가 변경한 RANDOM_PORT는 어떻게 포트를 랜덤하게 설정할까요?
그리고 어떻게 랜덤 설정된 포트를 가지고 올 수 있을까요?
RANDOM_PORT는 web application context를 로드 후, server.port=0 로 환경 변수를 지정하기만 합니다.
server.port=0의 의미
이렇게 설정된 profile을 토대로 실행된 Spring boot가 런타임 시점에 랜덤하게 포트를 스캔하여 ${local.server.port}에 생성한 값을 업데이트를 해놓게 되는 것입니다.
🙌 @LocalServerPort 사용하기
@LocalServerPort라는 어노테이션은 ${local.server.port}값을 가지고 옵니다.
이 어노테이션을 통해 현재 실행 중인 서버의 포트 번호를 가지고 올 수 있습니다.
이제 우리는 @LocalServerPort를 통해 각 테스트가 실행되기 전, 테스트 환경의 서버 포트를 가지고 오고,
가지고 온 후 바보 RestAssured에게 포트 값을 알려줄 수 있게 됩니다.
❤️ 성공
'우아한테크코스 6기 > 2단계' 카테고리의 다른 글
[방탈출 사용자 예약] @Bean, @Component, 그리고 POJO (0) | 2024.05.14 |
---|---|
영속성 entity 와 domain entity 분리해보기 (0) | 2024.05.12 |
[방탈출 예약 관리] 템플릿 엔진과 @RestController (0) | 2024.05.12 |
[방탈출 예약 관리] @DiritesContext, 알고 쓰자 (0) | 2024.04.27 |
[레벨2] 1주차 회고 (0) | 2024.04.27 |