[Spring] RestAssured로 API 테스트 진행하기
0. 들어가기 전에
API를 테스트하기 위해 RestAssured를 사용하게 되었는데, ''응답 값을 어떻게 테스트할까?' 하는 생각으로 사용 방법을 찾아봤습니다. 테스트 방식으로 REST-assured에서 나온 것처럼 then()
절 뒤에 body()
를 사용해서 테스트하는 방식과 JsonPath를 사용하는 방식이 있습니다. body()
를 사용하는 방식은 한 메서드의 길이가 길어지고 주로 사용하는 given / when / then 패턴
을 사용하기 어렵습니다.. 그래서 이 글에서는 JsonPath를 사용하여 테스트를 진행하는 방식을 소개하겠습니다.
1. RestAssured란?
REST 기반 서비스를 간단히 테스트하기 위한 Java DSL(Domain-Specific Languages)
DSL이라는게 와닿지 않을 수 있다. 쉽게 설명하면, 특정 영역의 문제를 해결하는 언어라고 생각하면 된다. 즉, RestAssured는 자바에서 사용하는 REST 기반 API를 테스트하는 도구라고 할 수 있다. RestAssured에 제공하는 HTTP 메서드( POST
, GET
, PUT
, DELETE
, HEAD
, PATCH
, OPTIONS
)를 이용해서 API를 쉽게 테스트할 수 있다.
2. JsonPath란?
JsonPath는 JSON 파일을 읽기 위한 Java DSL이다.
{
"lotto":{
"lottoId":5,
"winning-numbers":[2,45,34,23,7,5,3],
"winners":[{
"winnerId":23,
"numbers":[2,45,34,23,3,5]
},{
"winnerId":54,
"numbers":[52,3,12,11,18,22]
}]
}
}
예를 들어, 위 winnerId의 값들을 알려면 아래와 같이 .
을 이용한 이름 경로를 통해 값들을 추출할 수 있다.
List<Integer> winnerIds = response.jsonPath().getList("lotto.winners.winnerId");
// {23, 54}
3. RestAssured와 JsonPath를 사용해서 값 테스트
그렇다면 RestAssured로 어떻게 JsonPath를 얻을 수 있을까?
RestAssured는 extract()
메서드를 제공하는데, 이를 통해 ExtractableResponse<R>
를 얻을 수 있다.
ExtractableResponse<R>
의 상속구조는 위와 같다. ResponseBodyExtractionOptions
인터페이스의 jsonPath()
를 이용해서 JsonPath를 얻을 수 있다.
JsonPath를 얻으면, getString()
, getList()
와 같은 메서드를 사용해서, asserj와 junit으로 테스트 할 수 있다.
이제 테스트를 진행해보자.
아래와 같은 응답이 나오게 테스트 코드를 작성했다.
[응답]
HTTP/1.1 200
Content-Type: application/json
{
"winners": "브리",
"racingCars": [
{
"name": "브리",
"position": 9
},
{
"name": "토미",
"position": 7
},
{
"name": "브라운",
"position": 3
},
]
}
[Controller]
@Controller
public class RestAssuredController {
@PostMapping(value = "/rest")
public ResponseEntity<GameResponse> saveBoard(@RequestBody GameRequest request) {
final String[] names = request.getNames().split(",");
final RacingCarsDto name0 = new RacingCarsDto(names[0], 9);
final RacingCarsDto name1 = new RacingCarsDto(names[1], 7);
final RacingCarsDto name2 = new RacingCarsDto(names[2], 3);
final List<RacingCarsDto> cars = List.of(name0, name1, name2);
final GameResponse response = new GameResponse("브리", cars);
return ResponseEntity.ok(response);
}
}
[테스트 코드]
@SpringBootTest(webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT)
class RestAssuredControllerTest {
@LocalServerPort
int port;
@BeforeEach
void setUp() {
RestAssured.port = port;
}
@Test
void restAssuredTest() {
// given
final Map<String, Object> params = Map.of(
"names", "브리,토미,브라운",
"count", 10
);
// when
final ExtractableResponse<Response> response = RestAssured.given().log().all()
.contentType(MediaType.APPLICATION_JSON_VALUE)
.body(params)
.when().post("/rest")
.then().log().all()
.extract();
// then
final JsonPath result = response.jsonPath();
assertAll(
() -> assertThat(response.statusCode()).isEqualTo(HttpStatus.OK.value()),
() -> assertThat(result.getString("winners")).isEqualTo("브리"),
() -> assertThat(result.getList("racingCars.position", Integer.class))
.containsExactly(9, 7, 3)
);
}
}
위의 코드는 모두 성공하는 코드이며, 테스트 방법 요약을 다음과 같다.
- RestAssured를 통해 API를 호출한다.
extract()
메서드를 통해ExtractableResponse
를 얻는다.jsonPath()
메서드를 통해 JsonPath를 얻는다.- 경로를 통해 값들을 확인한다.
※ 출처
'FRAMEWORK > [SPRING]' 카테고리의 다른 글
[Spring] Spring에서 Bean은 어떤 자료구조로 관리될까요? (0) | 2023.04.22 |
---|---|
[Spring] Spring에서 DI하는 3가지 방법 (1) | 2023.04.21 |
[Spring] Spring ArgumentResolver란? (0) | 2022.08.10 |
[Spring] 스프링 필터(Filter) vs 인터셉터(Interceptor) (0) | 2022.08.09 |
[Spring] Jar vs War (0) | 2022.06.27 |