1. 概述
在测试REST端点时,有时我们希望获取响应并将其转换为对象以进行进一步检查和验证。众所周知,一种方法是使用RestAssured等库来验证响应,而无需将其转换为对象。
在本教程中,我们将探讨使用MockMVC和Spring Boot将JSON内容作为对象获取的几种方法。
2. 示例设置
在深入研究之前,让我们创建一个用于测试的简单REST端点。
让我们从依赖设置开始,我们将spring-boot-starter-web依赖添加到pom.xml中,以便我们可以创建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 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());
}
在这里,我们为Article元素列表定义了TypeToken。然后,在fromJson()方法中,我们调用getType()来返回Type对象。Gson使用反射来确定我们要将JSON转换为哪种类型的对象。
6. 总结
在本文中,我们学习了使用MockMVC工具时将JSON内容作为对象检索的几种方法。
总而言之,我们可以使用Jackson的ObjectMapper将String响应转换为所需的类型。处理集合时,我们需要指定TypeReference或CollectionType。同样,我们可以使用Gson库反序列化对象。
Post Directory
