Spring MVC测试框架入门–第1部分
最新推出的主要Spring框架是Spring MVC测试框架,Spring Guys声称它是“一流的JUnit支持,可通过流畅的API测试客户端和服务器端Spring MVC代码” 1 。 在这个博客以及下一个博客中,我将看一看Spring的MVC测试框架,并将其应用于我现有的一些示例代码中,以弄清它是否能如其所愿。
已使用两种设置服务器端测试的方式来设计API。 首先,它们带有Spring上下文文件,其次,以编程方式没有上下文文件。 Spring的Guy将该程序化方法称为“独立”模式。
以编程方式设置测试似乎更类似于单元测试,并且最好用于对特定的控制器类进行独立于其协作者的单元测试。 另一方面,加载Spring上下文文件的操作实际上是集成测试,并且更适合端到端测试。
您可以在此处找到有关测试技术的博客的完整列表。
如果您像我一样,那么您已经在使用现有的框架(例如Mockito或Easymock)来测试您的控制器。 通常的Mockito / Easymock方法是实例化您的控制器,注入模拟或存根依赖性,然后调用被测方法,注意返回值或验证模拟方法调用。
Spring Mvc Test框架与其他模拟框架采用不同的方法,因为它加载Spring DispatcherServlet来模拟Web容器的操作。 然后,将被测试的控制器加载到Spring上下文中,并由DispatcherServlet对其进行访问,就像在“现实生活”中一样。
这种方法的好处是,它允许您将控制器作为控制器而不是POJO进行测试。 这意味着将处理并考虑控制器的注释,执行验证并以正确的顺序调用方法。
您是否同意这种方法,并取决于您对测试技术的看法。 如果您认为应该将测试的每个类/方法都隔离到第n个级别,并且每个测试都应完全原子化,那么这可能不适合您。 如果您比较务实,并且可以将测试控制器的好处看作是……一个控制器,那么可能会对这个框架感兴趣。
与Mockito和Easymock的方法有所不同,缺点是代码看起来与这些较旧的,已建立的技术不同。 它在很大程度上依赖于构建器模式来构造匹配器,请求构建器和处理程序,一旦掌握了一切,这一切都是有道理的。 我怀疑使用构建器模式的动机是为了简化模拟HttpServletRequest
的设置以及对模拟HttpServletResponse
对象的询问,这在定义上可能非常棘手。
在本博客中,我将看一下Spring API的编程/独立技术,并将其与类似的基于Mockito的单元测试进行比较。
为了加快处理速度,我使用了Blue Peter方法“这是我之前准备的方法”,并从我的Facebook博客中获取了FacebookPostsController
,我将为此编写两个单元测试类:第一个使用Mockito,另一个使用Spring Mvc测试API。
控制器代码如下所示:
@Controller
public class FacebookPostsController { private static final Logger logger = LoggerFactory .getLogger(FacebookPostsController.class); @Autowired private SocialContext socialContext; @RequestMapping(value = "posts", method = RequestMethod.GET) public String showPostsForUser(HttpServletRequest request, HttpServletResponse response, Model model) throws Exception { String nextView; if (socialContext.isSignedIn(request, response)) { List<Post> posts = retrievePosts(); model.addAttribute("posts", posts); nextView = "show-posts"; } else { nextView = "signin"; } return nextView; } private List<Post> retrievePosts() { Facebook facebook = socialContext.getFacebook(); FeedOperations feedOps = facebook.feedOperations(); List<Post> posts = feedOps.getHomeFeed(); logger.info("Retrieved " + posts.size() + " posts from the Facebook authenticated user"); return posts; }
}
我不打算讲这段代码的背景,因为它可以在Facebook博客中找到 。 但是,总而言之,Facebook示例应用程序访问用户的Facebook帐户并在示例应用程序中显示其新闻提要。 为此, FacebookPostsController
检查SocialContext
类,以确定用户是否已登录其Facebook帐户。 如果用户登录到其Facebook帐户,则控制器将检索用户的帖子并将其添加到模型中以进行显示。 另一方面,如果用户未登录,则将他们定向到登录页面。
两个单元测试类中的每一个都将包含三个公共方法:
我将依次检查setup()
, testShowPostsForUser_user_is_not_signed_in
和testShowPostsForUser_user_is_signed_in
。
如您所料,测试testShowPostsForUser_user_is_not_signed_in
和testShowPostsForUser_user_is_signed_in
用于测试用户登录和未登录其Facebook帐户的情况。
“标准” Mockito测试
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); }
设置代码相当简单,包含三个简单步骤:
- 使用
MockitoAnnotations.initMocks(this)
初始化模拟对象。 - 创建一个新的
FacebookPostsController
实例,它是被测试的对象。 - 将模拟的
SocialContext
注入FacebookPostsController
。
@Test public void testShowPostsForUser_user_is_not_signed_in() throws Exception { when(socialContext.isSignedIn(request, response)).thenReturn(false); String result = instance.showPostsForUser(request, response, model); assertEquals("signin", result); }
testShowPostsForUser_user_is_not_signed_in
方法将模拟的SocialContext
配置为在调用其isSignedIn()
方法时返回false
。 这意味着剩下要做的就是断言showPostsForUser(...)
方法返回"signin"
将用户定向到登录页面。
@Test public void testShowPostsForUser_user_is_signed_in() throws Exception { when(socialContext.isSignedIn(request, response)).thenReturn(true); when(socialContext.getFacebook()).thenReturn(facebook); when(facebook.feedOperations()).thenReturn(feedOps); List<Post> posts = Collections.emptyList(); when(feedOps.getHomeFeed()).thenReturn(posts); String result = instance.showPostsForUser(request, response, model); verify(model).addAttribute("posts", posts); assertEquals("show-posts", result); }
testShowPostsForUser_user_is_signed_in
稍微复杂一些。 在将模拟的SocialContext
配置为在调用其isSignedIn()
方法时返回true
,还有另外四行代码可确保从模拟Facebook提要中返回posts
列表并将其添加到模拟Model
。 调用showPostsForUser(...)
之后,需要完成两个附加步骤:验证模拟Model
包含posts
列表,以及断言showPostsForUser(...)
的返回值为"show-posts"
。
接下来,Spring MVC Test框架代码; 但是,在开始之前,您需要将以下依赖项添加到POM文件:
<dependency><groupId>org.springframework</groupId><artifactId>spring-test</artifactId><version>${org.springframework-version}</version><scope>test</scope></dependency>
Spring MVC测试
Spring MVC测试框架版本运行相同的两个测试,但是方式不同……
@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); FacebookPostsController instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); mockMvc = MockMvcBuilders.standaloneSetup(instance).build(); }
如果看一下上面的代码,就可以看到,就setup(...)
而言,它看起来与上面的直接Mockito代码非常相似。 像基于Mockito的测试一样,第一步是使用初始化模拟对象
MockitoAnnotations.initMocks(this)
,然后创建一个FacebookPostsController
的新实例,将模拟的SocialContext
注入到该实例中。 但是,这一次, FacebookPostsController
状态已降级为局部变量,因为设置的重点是创建一个Spring的MockMvc
实例,该实例用于执行测试。 该mockMvc
是通过调用创建MockMvcBuilders.standaloneSetup(instance).build()
其中instance
是FacebookPostsController
对象,我们正在测试。
@Test public void testShowPostsForUser_user_is_not_signed_in() throws Exception { HttpServletRequest request = anyObject(); HttpServletResponse response = anyObject(); when(socialContext.isSignedIn(request, response)).thenReturn(false); MockHttpServletRequestBuilder getRequest = get("/posts").accept(MediaType.ALL); ResultActions results = mockMvc.perform(getRequest); results.andExpect(status().isOk()); results.andExpect(view().name("signin")); }
与Mockito版本类似, testShowPostsForUser_user_is_not_signed_in
方法将模拟的SocialContext
配置为在调用其isSignedIn()
方法时返回false
。 这次,下一步是使用静态方法创建一个称为MockHttpServletRequestBuilder
东西。
MockMvcRequestBuilders.get(...)
和构建器模式。 它被传递到mockMVC.perform(...)
方法中,在此方法中,该方法用于创建MockHttpServletRequest
对象,该对象用于定义测试的起点。 在此测试中,我要做的只是传递"/posts"
URL并将输入设置为“ any”媒体类型。 您可以使用诸如contentType()
, contextPath()
, cookie()
等方法配置许多其他请求对象属性。有关更多信息,请查看Spring Javadoc中的MockHttpServletRequest
mockMvc.perform()
方法返回一个ResultActions
对象。 这似乎是实际MvcResult
的包装。 ResultsActions
是一个便捷对象,用于以与JUnit的assertEquals(...)
或Mockito的verify(..)
方法相同的方式声明测试结果。 在这种情况下,我正在检查结果Http状态是否正常(即200),并且下一个视图将"signin"
。
此测试与仅Mockito版本之间的区别在于,您不是直接测试对测试实例的方法调用的结果; 您正在测试方法调用生成的HttpServletResponse
对象。
@Test public void testShowPostsForUser_user_is_signed_in() throws Exception { HttpServletRequest request = anyObject(); HttpServletResponse response = anyObject(); when(socialContext.isSignedIn(request, response)).thenReturn(true); when(socialContext.getFacebook()).thenReturn(facebook); when(facebook.feedOperations()).thenReturn(feedOps); List<Post> posts = Collections.emptyList(); when(feedOps.getHomeFeed()).thenReturn(posts); mockMvc.perform(get("/posts").accept(MediaType.ALL)).andExpect(status().isOk()) .andExpect(model().attribute("posts", posts)) .andExpect(view().name("show-posts")); }
testShowPostsForUser_user_is_signed_in
方法的Spring Test版本与Mockito版本非常相似,该测试是通过将SocialContext.isSignedIn()
方法配置为返回true
以及feedOps.getHomeFeed()
配置为返回posts
列表来准备测试的。 此方法的Spring Mvc Test部分与上述testShowPostsForUser_user_is_not_signed_in
版本几乎相同,不同之处在于,这次它使用andExpect(view().name("show-posts")
检查下一个视图名称"show-posts"
而不是"sign-in"
andExpect(view().name("show-posts")
我在这里使用的代码样式与我在上面使用的样式有些不同,并且是Spring的Guy偏爱的样式。如果您能在Github上找到更多这种样式的示例,持有Spring MVC Showcase应用。
那么,您可以从此比较中得出什么结论? 公平地说,这不是真正的比较– Spring MVC Test API在建立标准Mockito技术的基础上,采用了不同的方法,创建了一个框架,旨在仅在其本机运行时环境的模型中对Spring MVC控制器进行测试。 。
这对您是否有用,我会让您决定。 它确实具有将控制器视为控制器而不是POJO的优点,这意味着它们已经过更彻底的测试。 从个人的角度来看,我喜欢加载Spring配置文件并将其用于集成测试的想法,这将在我的下一个博客中介绍。
- 1请参阅: http : //static.springsource.org/spring/docs/3.2.x/spring-framework-reference/html/testing.html#spring-mvc-test-framework
- 该博客的代码可在GitHub上找到: https : //github.com/roghughe/captaindebug/tree/master/facebook
翻译自: https://www.javacodegeeks.com/2013/07/getting-started-with-springs-mvc-test-framework-part-1.html
Spring MVC测试框架入门–第1部分相关推荐
- Spring MVC测试框架入门–第2部分
这个迷你系列的第一个博客介绍了Spring MVC测试框架,并展示了其在单元测试Spring MVC Controller类中作为控制器而不是POJO进行单元测试的用途. 现在是时候讨论使用框架进行集 ...
- spring框架mvc框架_Spring的MVC测试框架入门–第1部分
spring框架mvc框架 最新推出的主要Spring框架是Spring MVC测试框架,Spring Guys声称它是"一流的JUnit支持,可通过流畅的API测试客户端和服务器端Spri ...
- spring框架mvc框架_Spring MVC测试框架入门–第2部分
spring框架mvc框架 这个迷你系列的第一个博客介绍了Spring MVC测试框架,并演示了其在单元测试Spring MVC Controller类中作为控制器而不是POJO进行单元测试的用途. ...
- Spring MVC测试框架
原文链接:http://jinnianshilongnian.iteye.com/blog/2004660 Spring MVC测试框架详解--服务端测试 博客分类: springmvc杂谈 spri ...
- 14.6 Spring MVC 测试框架(翻译)
14.6 Spring MVC 测试框架(每天翻译一点点) Spring MVC测试框架对 Spring MVC 代码提供一流的测试支持 ,它拥有一个 fluent API ,可以和JUnit, Te ...
- Spring MVC测试框架详解——服务端测试
随着RESTful Web Service的流行,测试对外的Service是否满足期望也变的必要的.从Spring 3.2开始Spring了Spring Web测试框架,如果版本低于3.2,请使用sp ...
- spring mvc + mybatis 框架搭建 ( idea + gradle)
spring mvc + mybatis 框架搭建 idea + gradle 刚刚入门,只是个人见解,如有错误或者问题欢迎指出指正. 邮箱: [ wgh0807@qq.com ] 文章引用: [ap ...
- Spring MVC 4快速入门Maven原型已改进
Spring Boot使Spring入门非常容易. 但是仍然有人对不使用Spring Boot并以更经典的方式引导应用程序感兴趣. 几年前,我创建了一个原型(早于Spring Boot),简化了引导S ...
- Spring MVC的框架组件
Spring MVC的框架组件 DispatcherServlet:前端控制器 用户请求到达前端控制器,它相当于MVC中的C,dispatcherServlet没有处理业务的能力,它是整个流程的控制中 ...
最新文章
- 深度学习中的网络表征学习的算法目标简介
- android 标题图标,android 中 actionbar 常用方法。设置标题,隐藏图标等
- python重命名文件源码
- php fpm 不写errorlog,PHP-FPM不写入错误日志
- Redis布隆过滤器
- 飞桨PaddleHub实现皮影戏
- azure 导入 bak_如何使用BULK INSERT在本地和Azure中导入数据
- unrecognized selector sent to instance的一类解决办法
- 动态规划 分享巧克力 4794_包装|颇具艺术欣赏性的巧克力创意包装设计
- 手把手教你学DSP 28335学习笔记
- 使用RF测试时,如何自动关闭浏览器驱动进程
- 微信小程序错误码:“errcode“:40163和微信小程序-pad block corrupted 问题
- 将自己的主页地址设置为OpenID
- 多媒体数字互动技术的应用有哪些?
- MSOCache是什么文件啊?
- 浅谈一下pyd文件的逆向
- 基于java的人力资源管理系统_基于Java Web的企业人力资源管理系统的设计与实现(样例3)...
- Efficient Frontier of Two Risky Assets(两种证券组合的有效边界)
- 软件工程导论第3章习题答案
- 仙居机器人_【101梦想秀】不得了!他是仙居机器人领域的领跑者!
热门文章
- spring boot actuator 入门荔枝
- tomcat(11)org.apache.catalina.core.StandardWrapper源码剖析
- 代码大全和新月神话_神话般的代码
- java 迁移数据_Java 10迁移建议
- mega2560单片机开发_[MEGA DEAL] Ultimate Java开发和认证指南(59%折扣)
- jboss性能指标_JBoss BRMS复杂事件处理(CEP)性能基准
- java 不同类型 映射_如何使用Java泛型映射不同的值类型
- ejb生命周期_EJB 3.x:生命周期和并发模型(第1部分)
- JDK 13:什么是AggressiveOpts?
- martin fowler_用Java和Java 8创建内部DSL,采用Martin Fowler的方法