如何测试Spring|如何测试Spring MVC应用
Spring的依赖注入使得我们的代码非常容易进行单元测试——@Controller
, @Service
,@Entity
等注解标注的类基本都是POJO(plain old Java object),也就是说很少依赖于Spring容器本身的API。我们可以非常容易地使用JUnit或TestNG编写测试代码。另一方面,对于三层架构的Spring Web应用(Controller, Service, DAO),使用Mock活Stub方法也能够更好的来测试我们的代码逻辑。例如Service层代码的单元测试中,依赖的DAO(或Repository)对象都是根据应用测试需求Mock出来的,而不需要真正去访问数据库。
Spring Web测试
在对Spring Web应用中的@Controller
代码进行单元测试的过程中,一般的方法是创建@Controller
对象,同时将它依赖的一些Mock对象——例如MockHttpServletRequest, MockHttpServletResponse(都由spring-test模块提供,无需自己编写)作为@Controller方法的参数。但是对于处理Web请求的@Controller代码来说,仅仅测试Handler方法里的代码是远远不够的,对于一个处理HTTP请求的@Controller`,我们还需要测试:
@RequestMapping
路由是否正确- 数据绑定、类型转换、校验逻辑是否正确——数据包括URL参数、表单、
@PathVariable
等 @InitBinder
,@ModelAttribute
,@ExceptionHandler
等注解的方法或属性计算过程
@Controller
代码单元测试的概念,应该做一些扩充——不仅仅局限于代码本身,也要结合MVC框架中的各个处理过程。本文接下来的内容代码,都以Spring Boot为例,首先假设我们通过Spring Boot创建了一个最简单的Web Mvc应用——包含了一个最简单的Conroller,处理
/users/{id}
对应的HTTP请求,返回值是id={id}
(通过String.format()
方法),那么可以为它创建如下测试代码:import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.content; import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status; @RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = SpringMvcTestDemoApplication.class)@WebAppConfigurationpublic class SpringMvcTestDemoApplicationTests {private MockMvc mockMvc; @Beforepublic void init() {this.mockMvc = MockMvcBuilders.standaloneSetup(new UserController()).build(); }@Testpublic void getUserById() throws Exception {long id = 1; this.mockMvc.perform(get("/users/" + id)).andExpect(status().isOk()).andExpect(content().string("id=" + id)); }}
运行上述测试时,很容易从控制台中的日志发现,
SpringJUnit4ClassRunner
创建了一个Spring Web应用上下文,并且在其中进行了Web Mvc框架的配置——这里是注册@RequestMapping
方法。接下来mockMvc.perform()
方法实际上向该Spring Web应用发起了一个HTTP请求:- 请求的url为
/users/{id}
andExpect()
方法也就是测试中常用的Assert
status()
用于检查返回状态吗,这里是200content()
用于检查内容
@RequestMapping
的路由路径写错,那么这里运行的结果一定不会是status().isOk()
,这也就完成了对HTTP请求路由的测试。接下来我们将继续探索MVC框架中的其他方面。Mock Service
在Spring Web应用三层结构里,Controller层代码通常会调用Service层代码,例如:
@RestControllerpublic class UserController {@Autowiredprivate UserService userService; @RequestMapping(value = "https://www.it610.com/users/{id}", method = GET)public String get(@PathVariable("id") long id) {String username = userService.getUsername(id); return String.format("username=%s", username); }}
对
UserController
进行单元测试需要排除Service代码的影响,所以需要对Service进行Mock,这里我们使用Mockito框架,在Spring上下文中Mock一个UserService
对象:@Configurationpublic class TestContext {@Beanpublic UserService userServiceMock() {return Mockito.mock(UserService.class); }}
同时通过
Mockito
的API来MockUserService.getUsername(long id)
方法,@Controller
的测试代码如下:@RunWith(SpringJUnit4ClassRunner.class)@SpringApplicationConfiguration(classes = {SpringMvcTestDemoApplication.class,TestContext.class})@WebAppConfigurationpublic class SpringMvcTestDemoApplicationTests {@AutowiredUserService userService; @AutowiredUserController controller; MockMvc mockMvc; @Beforepublic void init() {this.mockMvc = MockMvcBuilders.standaloneSetup(controller).build(); }@Testpublic void getUserById() throws Exception {long id = 1L; String ricky = "Ricky"; Mockito.when(userService.getUsername(id)).thenReturn(ricky); this.mockMvc.perform(get("/users/" + id)).andExpect(status().isOk()).andExpect(content().string("username=" + ricky)); }}
【如何测试Spring|如何测试Spring MVC应用】由于需要进行依赖注入,所以
UserService
和UserController
都使用@Autowired
注解。Mockito.when(userService.getUsername(id)).thenReturn(ricky)
;
表明userService.getUsername()
方法的参数为1L时,返回值为"Ricky
",Mockito提供能很多强大的Mock API,更多用法请参考官方文档。测试REST API
当我们构建REST服务时,大多数情况会使用JSON作为数据交换格式,Spring MVC测试框架同样提供了一种简洁的方式对JSON结果进行断言,假设现在有
@Controller
如下:@RequestMapping(value = "https://www.it610.com/users/{id}/json", method = GET)public User getUser(@PathVariable("id") long id) {String username = userService.getUsername(id); return new User(id, username); }static class User {public long id; public String username; //构造方法,Getter/Setter略}
实际应用返回的JSON数据是:
{ "id": 1, "username": "Ricky"}
测试代码可以这样断言:
@Testpublic void getUser() throws Exception {this.mockMvc.perform(get("/users/{id}/json", id).accept(MediaType.APPLICATION_JSON)).andExpect(status().isOk()).andExpect(jsonPath("$.id").value(id.intValue())).andExpect(jsonPath("$.username").value(ricky)); }
$.id
, $.username
都是JsonPath提供的JSON表达式,可以通过jsonPath
、value()
等方法来轻松对JSON数据进行断言而不需要自己编写JSON文本处理。以上就是如何测试Spring MVC应用的详细内容,更多关于测试Spring MVC应用的资料请关注脚本之家其它相关文章!
推荐阅读
- 考研英语阅读终极解决方案——阅读理解如何巧拿高分
- 如何寻找情感问答App的分析切入点
- Activiti(一)SpringBoot2集成Activiti6
- mybatisplus如何在xml的连表查询中使用queryWrapper
- MybatisPlus使用queryWrapper如何实现复杂查询
- SpringBoot调用公共模块的自定义注解失效的解决
- 解决SpringBoot引用别的模块无法注入的问题
- 如何在Mac中的文件选择框中打开系统隐藏文件夹
- 漫画初学者如何学习漫画背景的透视画法(这篇教程请收藏好了!)
- java中如何实现重建二叉树