1. 概述
在測試我們的 REST 端點時,我們有時需要獲取響應並將其轉換為對象,以便進行進一步的檢查和驗證。正如我們所知,一種方法是使用諸如 RestAssured 之類的庫來驗證響應,而無需將其轉換為對象。
在本教程中,我們將探索使用 MockMVC 和 Spring Boot 以獲得 JSON 內容作為對象的一些方法。
2. 示例設置
在開始之前,讓我們創建一個簡單的 REST 端點,用於測試。
首先,讓我們進行依賴項設置。我們將向我們的 spring-boot-starter-web 添加依賴項,以便創建 REST 端點:
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-web</artifactId>
</dependency>
接下來,讓我們定義 Article 類:
public class Article {
private Long id;
private String title;
// standard getters and setters
}
進一步,讓我們創建一個 ArticleController 類,其中包含兩個端點,一個返回單個文章,另一個返回文章列表:
@RestController
@RequestMapping
public class ArticleController {
@GetMapping("/article")
public Article getArticle() {
return new Article(1L, "Learn Spring Boot");
}
@GetMapping("/articles")
public List<Article> getArticles() {
return List.of(new Article(1L, "Guide to JUnit"), new Article(2L, "Working with Hibernate"));
}
}
3. 測試類
為了測試我們的控制器,我們將用 @WebMvcTest 註解裝飾我們的測試類。當我們使用此註解時,Spring Boot 會自動配置 MockMvc 並僅啓動 Web 層級下的上下文。
此外,我們將僅實例化 ArticleController 控制器,這在具有多個控制器的應用程序中非常有用:
@WebMvcTest(ArticleController.class)
class ArticleControllerUnitTest {
@Autowired
private MockMvc mockMvc;
}
我們還可以使用 @AutoConfigureMockMvc 註解配置 MockMVC。但是,這種方法需要 Spring Boot 運行整個應用程序上下文,這會使我們的測試運行速度變慢。
現在我們已經完成了所有設置,讓我們探索如何使用 MockMvc 執行請求並以對象的形式獲取響應。
4. 使用 Jackson
將 JSON 內容轉換為對象的一種方式是使用 Jackson 庫。
4.1. 獲取單個對象
讓我們創建一個測試來驗證 HTTP GET /article 端點是否按預期工作。
由於我們希望將響應轉換為對象,首先在 mockMvc 上調用 andReturn() 方法以檢索結果:
MvcResult result = this.mockMvc.perform(get("/article"))
.andExpect(status().isOk())
.andReturn();
andReturn() 方法返回 MvcResult 對象,這允許我們執行工具不支持的附加驗證。
此外,我們可以調用 getContentAsString() 方法來檢索響應作為 String。 MockMvc 沒有定義的方法可以用來將響應轉換為特定對象類型。 我們需要自己指定邏輯。
我們將使用 Jackson 的 ObjectMapper 將 JSON 內容轉換為所需類型。
讓我們調用 readValue() 方法並將響應(格式為 String)以及我們想要轉換響應的類型傳遞:
String json = result.getResponse().getContentAsString();
Article article = objectMapper.readValue(json, Article.class);
assertNotNull(article);
assertEquals(1L, article.getId());
assertEquals("Learn Spring Boot", article.getTitle());
4.2. 獲取對象的集合
讓我們看看當端點返回集合時如何獲取響應。
在上一節中,當我們想要獲取單個對象時,我們指定了類型為 Article.class。 但是,對於泛型集合等類型,這不可行。 我們不能將類型指定為 List<Article>.class。
我們可以使用 Jackson 的 TypeReference 泛型類來反序列化集合:
@Test
void whenGetArticle_thenReturnListUsingJacksonTypeReference() throws Exception {
MvcResult result = this.mockMvc.perform(get("/articles"))
.andExpect(status().isOk())
.andReturn();
String json = result.getResponse().getContentAsString();
List<Article> articles = objectMapper.readValue(json, new TypeReference<>(){});
assertNotNull(articles);
assertEquals(2, articles.size());}
由於類型擦除,在運行時無法訪問泛型類型信息。 為了克服這一限制,TypeReference 在編譯時捕獲我們想要轉換 JSON 格式的類型。
此外,我們可以通過指定 CollectionType:
String json = result.getResponse().getContentAsString();
CollectionType collectionType = objectMapper.getTypeFactory().constructCollectionType(List.class, Article.class);
List<Article> articles = objectMapper.readValue(json, collectionType);
assertNotNull(articles);
assertEquals(2, articles.size());
5. 使用 Gson
現在,讓我們看看如何使用 Gson 庫將 JSON 內容轉換為對象。
首先,讓我們在 pom.xml 中添加所需的依賴項:
<dependency>
<groupId>com.google.code.gson</groupId>
<artifactId>gson</artifactId>
<version>2.10.1</version>
</dependency>
5.1. 獲取單個對象
我們可以通過調用 Gson 實例上的 fromJson() 方法,將 JSON 轉換為對象:
@Test
void whenGetArticle_thenReturnArticleObjectUsingGson() throws Exception {
MvcResult result = this.mockMvc.perform(get("/article"))
.andExpect(status().isOk())
.andReturn();
String json = result.getResponse().getContentAsString();
Article article = new Gson().fromJson(json, Article.class);
assertNotNull(article);
assertEquals(1L, article.getId());
assertEquals("Learn Spring Boot", article.getTitle());
}
5.2. 獲取對象的集合
最後,讓我們看看如何使用 Gson 處理集合。
要使用 Gson 反序列化集合,可以指定 TypeToken:
@Test
void whenGetArticle_thenReturnArticleListUsingGson() throws Exception {
MvcResult result = this.mockMvc.perform(get("/articles"))
.andExpect(status().isOk())
.andReturn();
String json = result.getResponse().getContentAsString();
TypeToken<List<Article>> typeToken = new TypeToken<>(){};
List<Article> articles = new Gson().fromJson(json, typeToken.getType());
assertNotNull(articles);
assertEquals(2, articles.size());
}
在這裏,我們定義了用於文章列表的 TypeToken。然後,在 fromJson() 方法中,我們調用 getType() 以返回 Type 對象。 Gson 使用反射來確定我們想要將 JSON 轉換為的對象的類型。
6. 結論
在本文中,我們學習瞭如何使用 MockMVC 工具將 JSON 內容作為對象檢索的方法。
總而言之,我們可以使用 Jackson 的 ObjectMapper 將 String 響應轉換為所需的類型。 在處理集合時,我們需要指定 TypeReference 或 CollectionType。 同樣,我們也可以使用 Gson 庫反序列化對象。