@SpringBootTest
- 통합테스트 하기에 적절
- 애플리케이션 컨텍스트를 로드하는데 시간이 걸려서 테스트가 다소 무거운 편이다.
- @SpringBootTest
- @BootstrapWith + @ExtendWith
- JUnit5를 사용 할때 @ExtendWith(SpringExtension.class) 쓰면 안된다.
- @Test
- JUnit5 애노테이션
- 단위 테스트 메소드 지정
@SpringBootTest properties
• value, properties: 프로퍼티 설정
• args: 애플리케이션 실행 시 커맨드라인으로 입력하는 인자(옵션) 설정
• classes: ApplicationContext 로딩을 위한 설정 클래스를 직접 지정
• webEnvironment: ApplicationContext 의 웹 환경 설정
• WebEnvironment.MOCK: mock servlet, embedded server 동작 x
• @AutoConfigureMockMvc, @AutoConfigureWebTestClient 와 함께 써서 mock test 가능
• WebEnvironment.RANDOM_PORT: 랜덤 포트, embedded server 동작
• WebEnvironment.DEFINED_PORT: 포트 지정(server.port), embedded server 동작
• WebEnvironment.NONE: 웹 환경 구성 안 함, embedded server 동작 x
Auto-configured Test(Slice Test)
- 스프링 애플리케이션에서 내가 필요한 일부분의 자동 설정만 불러오는 방법
• @DataCassandraTest
• @DataJdbcTest
• @DataJpaTest
• @DataLdapTest
• @DataMongoTest
• @DataNeo4jTest
• @DataR2dbcTest
• @DataRedisTest
• @JdbcTest
• @JooqTest
• @JsonTest
• @RestClientTest
• @WebFluxTest
• @WebMvcTest
• @WebServiceClientTest
@WebMvcTest
- spring mvc 컨트롤러 레이어를 슬라이스 테스트 할 때 사용
- mockmvc 빈을 자동 설정하고 테스트에 사용
- 로드할 컨트롤러 클래스를 지정 가능(기본 동작 : 전체 컨트롤러 로드)
@AutoConfigureMockMvc // MockMvc를 자동으로 구성하여 테스트에 사용
@SpringBootTest // 스프링 부트 애플리케이션을 로드하여 테스트를 실행
class BaseControllerTest {
@Autowired
private MockMvc mvc; // MockMvc를 주입하여 사용
@DisplayName("[view][GET] 기본 페이지 요청")
@Test // 테스트 메서드 선언
void testRoot() throws Exception {
// Given (주어진 상황)
// When (언제)
// Then (그러면)
mvc.perform(get("/")) // "/" 경로에 GET 요청 수행
.andExpect(status().isOk()) // HTTP 상태가 OK인지 확인
.andExpect(content().contentTypeCompatibleWith(MediaType.TEXT_HTML)) // 응답의 콘텐츠 타입이 text/html과 호환되는지 확인
.andExpect(content().string(containsString("default"))) // 응답 콘텐츠에 "default" 문자열이 포함되어 있는지 확인
.andExpect(view().name("index")) // 뷰의 이름이 "index"인지 확인
.andDo(print()); // 수행한 결과를 출력
}
}
테스트 결과
Slice Test로 변환(@WebMvcTest)
@WebMvcTest(BaseController.class) // BaseController를 테스트하기 위한 설정
class BaseControllerTest {
private final MockMvc mvc; // MockMvc 객체 선언
// 생성자 주입
public BaseControllerTest(@Autowired MockMvc mvc) {
this.mvc = mvc; // MockMvc 객체 주입
}
// APIPlaceController Test
@WebMvcTest(ApiPlaceController.class) // ApiPlaceController를 테스트하기 위한 웹 MVC 테스트
class ApiPlaceControllerTest {
private final MockMvc mvc; // MockMvc 객체 선언
public ApiPlaceControllerTest(@Autowired MockMvc mvc) { // 생성자를 통한 주입
this.mvc = mvc;
}
@DisplayName("[API][GET] 장소 리스트 조회 - 장소 리스트 데이터를 담은 표준 API 출력")
@Test // 테스트 메서드 선언
void givenNothing_whenRequestingPlaces_thenReturnsPlacesInStandardResponse() throws Exception {
// Given (주어진 상황)
// When & Then (언제 & 그러면)
mvc.perform(get("/api/places")) // "/api/places" 경로에 GET 요청 수행
.andExpect(status().isOk()) // HTTP 상태가 OK인지 확인
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) // 응답의 콘텐츠 타입이 JSON인지 확인
.andExpect(jsonPath("$.data").isArray()) // 응답 데이터의 "data" 필드가 배열인지 확인
.andExpect(jsonPath("$.data[0].placeType").value(PlaceType.COMMON.name())) // 첫 번째 데이터의 장소 타입이 COMMON인지 확인
.andExpect(jsonPath("$.data[0].placeName").value("랄라배드민턴장")) // 첫 번째 데이터의 장소 이름이 "랄라배드민턴장"인지 확인
.andExpect(jsonPath("$.data[0].address").value("서울시 강남구 강남대로 1234")) // 첫 번째 데이터의 주소가 "서울시 강남구 강남대로 1234"인지 확인
.andExpect(jsonPath("$.data[0].phoneNumber").value("010-1234-5678")) // 첫 번째 데이터의 전화번호가 "010-1234-5678"인지 확인
.andExpect(jsonPath("$.data[0].capacity").value(30)) // 첫 번째 데이터의 수용 가능 인원이 30인지 확인
.andExpect(jsonPath("$.data[0].memo").value("신장개업")) // 첫 번째 데이터의 메모가 "신장개업"인지 확인
.andExpect(jsonPath("$.success").value(true)) // 응답의 success 필드가 true인지 확인
.andExpect(jsonPath("$.errorCode").value(ErrorCode.OK.getCode())) // 응답의 errorCode 필드가 OK 코드인지 확인
.andExpect(jsonPath("$.message").value(ErrorCode.OK.getMessage())); // 응답의 message 필드가 OK 메시지인지 확인
}
@DisplayName("[API][GET] 단일 장소 조회 - 장소 있는 경우, 장소 데이터를 담은 표준 API 출력")
@Test // 테스트 메서드 선언
void givenPlaceId_whenRequestingExistentPlace_thenReturnsPlaceInStandardResponse() throws Exception {
// Given (주어진 상황)
int placeId = 1; // 장소 ID
// When & Then (언제 & 그러면)
mvc.perform(get("/api/places/" + placeId)) // "/api/places/{placeId}" 경로에 GET 요청 수행
.andExpect(status().isOk()) // HTTP 상태가 OK인지 확인
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) // 응답의 콘텐츠 타입이 JSON인지 확인
.andExpect(jsonPath("$.data").isMap()) // 응답 데이터의 "data" 필드가 Map인지 확인
.andExpect(jsonPath("$.data.placeType").value(PlaceType.COMMON.name())) // 장소 타입이 COMMON인지 확인
.andExpect(jsonPath("$.data.placeName").value("랄라배드민턴장")) // 장소 이름이 "랄라배드민턴장"인지 확인
.andExpect(jsonPath("$.data.address").value("서울시 강남구 강남대로 1234")) // 주소가 "서울시 강남구 강남대로 1234"인지 확인
.andExpect(jsonPath("$.data.phoneNumber").value("010-1234-5678")) // 전화번호가 "010-1234-5678"인지 확인
.andExpect(jsonPath("$.data.capacity").value(30)) // 수용 가능 인원이 30인지 확인
.andExpect(jsonPath("$.data.memo").value("신장개업")) // 메모가 "신장개업"인지 확인
.andExpect(jsonPath("$.success").value(true)) // 응답의 success 필드가 true인지 확인
.andExpect(jsonPath("$.errorCode").value(ErrorCode.OK.getCode())) // 응답의 errorCode 필드가 OK 코드인지 확인
.andExpect(jsonPath("$.message").value(ErrorCode.OK.getMessage())); // 응답의 message 필드가 OK 메시지인지 확인
}
@DisplayName("[API][GET] 단일 장소 조회 - 장소 없는 경우, 빈 표준 API 출력")
@Test // 테스트 메서드 선언
void givenPlaceId_whenRequestingNonexistentPlace_thenReturnsEmptyStandardResponse() throws Exception {
// Given (주어진 상황)
int placeId = 2; // 존재하지 않는 장소의 ID
// When & Then (언제 & 그러면)
mvc.perform(get("/api/places/" + placeId)) // "/api/places/{placeId}" 경로에 GET 요청 수행
.andExpect(status().isOk()) // HTTP 상태가 OK인지 확인
.andExpect(content().contentType(MediaType.APPLICATION_JSON)) // 응답의 콘텐츠 타입이 JSON인지 확인
.andExpect(jsonPath("$.data").isEmpty()) // 응답 데이터의 "data" 필드가 비어 있는지 확인
.andExpect(jsonPath("$.success").value(true)) // 응답의 success 필드가 true인지 확인
.andExpect(jsonPath("$.errorCode").value(ErrorCode.OK.getCode())) // 응답의 errorCode 필드가 OK 코드인지 확인
.andExpect(jsonPath("$.message").value(ErrorCode.OK.getMessage())); // 응답의 message 필드가 OK 메시지인지 확인
}
}
결과
'개발 > Spring' 카테고리의 다른 글
MVC 패턴(3) - 비즈니스 로직 구현 (0) | 2024.02.19 |
---|---|
Test Driven Development(TDD) (1) | 2024.02.18 |
ControllerAdvice (0) | 2024.02.17 |
MVC 패턴 - API 설계(2) (0) | 2024.02.17 |
함수형 프로그래밍 (0) | 2024.02.16 |