1. 概述
在本教程中,我們將討論如何使用 REST Assured 測試 REST 服務,重點是 捕獲和驗證來自我們 REST API 的響應數據。
2. 測試類設置
在之前的教程中,我們已經探討了REST Assured的一般用法,並展示瞭如何操作請求頭、Cookie和參數。
在此基礎上,我們添加了一個簡單的REST控制器,AppController,它內部調用了一個服務,AppService。我們將使用這些類在我們的測試示例中。
為了創建我們的測試類,我們需要進行一些設置。由於我們有spring-boot-starter-test在我們的classpath中,我們可以輕鬆地利用Spring測試實用程序。
首先,讓我們創建一個AppControllerIntegrationTest類的基本框架:
@RunWith(SpringRunner.class)
@SpringBootTest(webEnvironment = WebEnvironment.RANDOM_PORT)
public class AppControllerIntegrationTest {
@LocalServerPort
private int port;
private String uri;
@PostConstruct
public void init() {
uri = "http://localhost:" + port;
}
@MockBean
AppService appService;
//test cases
}
在本JUnit測試中,我們使用幾個Spring特定的註解對我們的類進行標註,這將在隨機可用的端口上啓動應用程序。在@PostConstruct中,我們捕獲了我們將要進行REST調用所使用的完整URI。
我們還使用@MockBean在AppService上,因為我們需要對該類的方法調用進行模擬。
3. Validating the JSON Response
JSON is the most common format used in REST APIs to exchange data. Responses can consist of a single JSON object or an array of JSON objects. We’ll look at both in this section.
3.1. Single JSON Object
Let’s say we need to test the /movie/{id} endpoint, which returns a Movie JSON object if the id is found.
We’ll mock AppService calls to return some mock data using the Mockito framework:
@Test
public void givenMovieId_whenMakingGetRequestToMovieEndpoint_thenReturnMovie() {
Movie testMovie = new Movie(1, "movie1", "summary1");
when(appService.findMovie(1)).thenReturn(testMovie);
get(uri + "/movie/" + testMovie.getId()).then()
.assertThat()
.statusCode(HttpStatus.OK.value())
.body("id", equalTo(testMovie.getId()))
.body("name", equalTo(testMovie.getName()))
.body("synopsis", notNullValue());
}
Above, we first mocked the appService.findMovie(1) call to return an object. Then, we constructed our REST URL in the get() method provided by REST Assured for making GET requests. Finally, we made four assertions.
First, we checked the response status code and then the body elements. We’re using Hamcrest to assert the expected value.
Also note that if the response JSON is nested, we can test a nested key by using the dot operator like “key1.key2.key3”.
3.2. Extracting the JSON Response After Validation
In some cases, we may need to extract the response after validation to perform additional operations on it.
We can extract the JSON response to a class, using the extract() method:
Movie result = get(uri + "/movie/" + testMovie.getId()).then()
.assertThat()
.statusCode(HttpStatus.OK.value())
.extract()
.as(Movie.class);
assertThat(result).isEqualTo(testMovie);
In this example, we directed REST Assured to extract the JSON response to a Movie object and then asserted on the extracted object.
We can also extract the whole response to a String, using the extract().asString() API:
String responseString = get(uri + "/movie/" + testMovie.getId()).then()
.assertThat()
.statusCode(HttpStatus.OK.value())
.extract()
.asString();
assertThat(responseString).isNotEmpty();
Finally, we can extract a particular field out of the response JSON as well.
Let’s look at a test for a POST API that expects a Movie JSON body and will return the same if inserted successfully:
@Test
public void givenMovie_whenMakingPostRequestToMovieEndpoint_thenCorrect() {
Map<String, String> request = new HashMap<>();
request.put("id", "11");
request.put("name", "movie1");
request.put("synopsis", "summary1");
int movieId = given().contentType("application/json")
.body(request)
.when()
.post(uri + "/movie")
.then()
.assertThat()
.statusCode(HttpStatus.CREATED.value())
.extract()
.path("id");
assertThat(movieId).isEqualTo(11);
}
Above, we first made the request object that we need to POST. We then extracted the id field from the returned JSON response using the path() method.
3.3. JSON Array
We can also verify the response if it’s a JSON array:
@Test
public void whenCallingMoviesEndpoint_thenReturnAllMovies() {
Set<Movie> movieSet = new HashSet<>();
movieSet.add(new Movie(1, "movie1", "summary1"));
movieSet.add(new Movie(2, "movie2", "summary2"));
when(appService.getAll()).thenReturn(movieSet);
get(uri + "/movies").then()
.statusCode(HttpStatus.OK.value())
.assertThat()
.body("size()", is(2));
}
Accordingly, we first mocked the appService.getAll() method with some data and made a request to our endpoint. We then asserted the statusCode and size of our response array.
This again can be done via extraction:
Movie[] movies = get(uri + "/movies").then()
.statusCode(200)
.extract()
.as(Movie[].class);
assertThat(movies.length).isEqualTo(2);
}
3.4. Deserializing Response JSON as List<POJO>
In the previous section, we deserialized a JSON array of movies into a Java array of Movie objects using .as(Movie[].class). While this works, a more idiomatic approach in Java is to use a generic List.
However, we can’t make a direct deserialization to a generic type like List.class because of Java’s type erasure. This is because REST Assured, which uses Jackson, can’t determine the generic type (Movie) at runtime.
To solve this, we use the TypeRef class in REST Assured, which is an abstract class that enables us to pass generic type information to the deserializer:
@Test
public void givenSetMovie_whenCallingMoviesEndpoint_thenReturnAllMoviesAsList() {
Set<Movie> movieSet = new HashSet<>();
movieSet.add(new Movie(1, "movie1", "summary1"));
movieSet.add(new Movie(2, "movie2", "summary2"));
when(appService.getAll()).thenReturn(movieSet);
List<Movie> movies = get(uri + "/movies").then()
.statusCode(200)
.extract()
.as(new TypeRef<List<Movie>>() {});
assertThat(movies.size()).isEqualTo(2);
}
Thus, by creating an anonymous inner class extending TypeRef<List>, we explicitly tell REST Assured the exact generic type we want to deserialize the response body into. This neatly deserializes the response into a List, which is much cleaner to work with than a Movie[] array.
4. 驗證頭部和 Cookie
我們可以使用同名的方法來驗證響應的頭部或 Cookie:
@Test
public void whenCallingWelcomeEndpoint_thenCorrect() {
get(uri + "/welcome").then()
.assertThat()
.header("sessionId", notNullValue())
.cookie("token", notNullValue());
}
我們還可以分別提取頭部和 Cookie:
Response response = get(uri + "/welcome");
String headerName = response.getHeader("sessionId");
String cookieValue = response.getCookie("token");
assertThat(headerName).isNotBlank();
assertThat(cookieValue).isNotBlank();
5. 驗證文件
如果我們的 REST API 返回一個文件,我們可以使用 asByteArray() 方法來提取響應:
File file = new ClassPathResource("test.txt").getFile();
long fileSize = file.length();
when(appService.getFile(1)).thenReturn(file);
byte[] result = get(uri + "/download/1").asByteArray();
assertThat(result.length).isEqualTo(fileSize);
在這裏,我們首先對 appService.getFile(1) 進行模擬,以返回位於我們 src/test/resources 路徑中的文本文件。然後,我們調用了我們的端點並以 byte[] 提取響應,然後斷言其值為預期值。
6. 結論
在本教程中,我們探討了使用 REST Assured 從我們的 REST API 中捕獲和驗證響應的不同方法。