最新推出的主要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_intestShowPostsForUser_user_is_signed_in

如您所料,测试testShowPostsForUser_user_is_not_signed_intestShowPostsForUser_user_is_signed_in用于测试用户登录和未登录其Facebook帐户的情况。

“标准” Mockito测试

@Before public void setUp() throws Exception { MockitoAnnotations.initMocks(this); instance = new FacebookPostsController(); ReflectionTestUtils.setField(instance, "socialContext", socialContext); }

设置代码相当简单,包含三个简单步骤:

  1. 使用MockitoAnnotations.initMocks(this)初始化模拟对象。
  2. 创建一个新的FacebookPostsController实例,它是被测试的对象。
  3. 将模拟的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()其中instanceFacebookPostsController对象,我们正在测试。

@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
参考: Spring的MVC测试框架入门–来自我们的JCG合作伙伴 Roger Hughes的第1部分 ,位于Captain Debug的Blog博客上。

翻译自: https://www.javacodegeeks.com/2013/07/getting-started-with-springs-mvc-test-framework-part-1.html

Spring MVC测试框架入门–第1部分相关推荐

  1. Spring MVC测试框架入门–第2部分

    这个迷你系列的第一个博客介绍了Spring MVC测试框架,并展示了其在单元测试Spring MVC Controller类中作为控制器而不是POJO进行单元测试的用途. 现在是时候讨论使用框架进行集 ...

  2. spring框架mvc框架_Spring的MVC测试框架入门–第1部分

    spring框架mvc框架 最新推出的主要Spring框架是Spring MVC测试框架,Spring Guys声称它是"一流的JUnit支持,可通过流畅的API测试客户端和服务器端Spri ...

  3. spring框架mvc框架_Spring MVC测试框架入门–第2部分

    spring框架mvc框架 这个迷你系列的第一个博客介绍了Spring MVC测试框架,并演示了其在单元测试Spring MVC Controller类中作为控制器而不是POJO进行单元测试的用途. ...

  4. Spring MVC测试框架

    原文链接:http://jinnianshilongnian.iteye.com/blog/2004660 Spring MVC测试框架详解--服务端测试 博客分类: springmvc杂谈 spri ...

  5. 14.6 Spring MVC 测试框架(翻译)

    14.6 Spring MVC 测试框架(每天翻译一点点) Spring MVC测试框架对 Spring MVC 代码提供一流的测试支持 ,它拥有一个 fluent API ,可以和JUnit, Te ...

  6. Spring MVC测试框架详解——服务端测试

    随着RESTful Web Service的流行,测试对外的Service是否满足期望也变的必要的.从Spring 3.2开始Spring了Spring Web测试框架,如果版本低于3.2,请使用sp ...

  7. spring mvc + mybatis 框架搭建 ( idea + gradle)

    spring mvc + mybatis 框架搭建 idea + gradle 刚刚入门,只是个人见解,如有错误或者问题欢迎指出指正. 邮箱: [ wgh0807@qq.com ] 文章引用: [ap ...

  8. Spring MVC 4快速入门Maven原型已改进

    Spring Boot使Spring入门非常容易. 但是仍然有人对不使用Spring Boot并以更经典的方式引导应用程序感兴趣. 几年前,我创建了一个原型(早于Spring Boot),简化了引导S ...

  9. Spring MVC的框架组件

    Spring MVC的框架组件 DispatcherServlet:前端控制器 用户请求到达前端控制器,它相当于MVC中的C,dispatcherServlet没有处理业务的能力,它是整个流程的控制中 ...

最新文章

  1. 深度学习中的网络表征学习的算法目标简介
  2. android 标题图标,android 中 actionbar 常用方法。设置标题,隐藏图标等
  3. python重命名文件源码
  4. php fpm 不写errorlog,PHP-FPM不写入错误日志
  5. Redis布隆过滤器
  6. 飞桨PaddleHub实现皮影戏
  7. azure 导入 bak_如何使用BULK INSERT在本地和Azure中导入数据
  8. unrecognized selector sent to instance的一类解决办法
  9. 动态规划 分享巧克力 4794_包装|颇具艺术欣赏性的巧克力创意包装设计
  10. 手把手教你学DSP 28335学习笔记
  11. 使用RF测试时,如何自动关闭浏览器驱动进程
  12. 微信小程序错误码:“errcode“:40163和微信小程序-pad block corrupted 问题
  13. 将自己的主页地址设置为OpenID
  14. 多媒体数字互动技术的应用有哪些?
  15. MSOCache是什么文件啊?
  16. 浅谈一下pyd文件的逆向
  17. 基于java的人力资源管理系统_基于Java Web的企业人力资源管理系统的设计与实现(样例3)...
  18. Efficient Frontier of Two Risky Assets(两种证券组合的有效边界)
  19. 软件工程导论第3章习题答案
  20. 仙居机器人_【101梦想秀】不得了!他是仙居机器人领域的领跑者!

热门文章

  1. spring boot actuator 入门荔枝
  2. tomcat(11)org.apache.catalina.core.StandardWrapper源码剖析
  3. 代码大全和新月神话_神话般的代码
  4. java 迁移数据_Java 10迁移建议
  5. mega2560单片机开发_[MEGA DEAL] Ultimate Java开发和认证指南(59%折扣)
  6. jboss性能指标_JBoss BRMS复杂事件处理(CEP)性能基准
  7. java 不同类型 映射_如何使用Java泛型映射不同的值类型
  8. ejb生命周期_EJB 3.x:生命周期和并发模型(第1部分)
  9. JDK 13:什么是AggressiveOpts?
  10. martin fowler_用Java和Java 8创建内部DSL,采用Martin Fowler的方法