1. 概述
在测试我们的REST端点时,有时我们需要获取响应并将其转换为对象以便进一步检查和验证。众所周知,一种方法是使用像RestAssured这样的库来验证响应,而无需将其转换为对象。
在这个教程中,我们将探讨使用MockMVC和Spring Boot以几种方式获取JSON内容并作为对象进行操作的方法。
2. 示例设置
在深入之前,让我们创建一个简单的用于测试的REST端点。
首先,设置依赖。我们需要在pom.xml
中添加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 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使用反射(Java反射)来确定我们想要将JSON转换为什么类型的对象。
6. 总结
在这篇文章中,我们学习了在使用MockMVC工具时获取JSON内容作为对象的几种方法。
总之,我们可以使用Jackson的ObjectMapper
将String
响应转换为目标类型。在处理集合时,我们需要指定TypeReference
或CollectionType
。同样,我们也可以使用Gson库来反序列化对象。
如往常一样,完整的源代码可以在GitHub上找到。