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

spring框架mvc框架

最新推出的主要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对象的询问,这从定义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,来自Captain Debug的Blog博客。

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

spring框架mvc框架

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/347256.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

最小拍无纹波系统仿真实验(计控实验五simulink)

一、实验目的与要求 1、掌握最小拍无纹波系统的计算机控制脉冲传函D(z)的设计方法。 2、掌握SIMULINK的仿真方法。 二、仿真软硬件环境 PC机&#xff0c;MATLAB R2012b。 三、实验原理 如图 R为输入&#xff0c;C为输出。计算机定时采样&#xff0c;计算误差E&#xff0c;按D…

OpenMP之双重for循环并行计算改进

这篇文章是基于OpenMP对Github项目schneider_et_al_2016_animaldiversity进行计算速度改进,关于该项目请参考博客: Windows10+VS2017下GSL1.8_x86和sundials2.5.0配置及GITHUB项目schneider_et_al_2016_animaldiversity编译运行 项目设置 设置项目支持OpenMP,右键项目(pde…

Oracle ADF和Oracle Jet一起工作。 建筑模式

在本文中&#xff0c;我将考虑在Oracle ADF和Oracle Jet的组合之上实现应用程序的各种体系结构模式。 练习ADF的组织可能会考虑将Oracle Jet合并到现有项目中&#xff0c;以刷新外观并使其具有现代感和响应能力&#xff0c;并以新方式实施新功能。 它可能会考虑将Oracle Jet用于…

基本指令的编程练习-PLC认识实验-定时器/计数器功能实验

微信公众号&#xff1a;创享日记 发送关键词&#xff1a;plc1 免费获取完整无水印实验报告 【PLC认识实验】 一、实验目的 1.了解PLC软硬件结构及系统组成; 2.掌握PLC外围直流控制及负载线路的接法及上位计算机与PLC通信参数的设置; 3.了解编程软件的编程环境&#xff0c;掌握软…

C语言实用算法系列之strtok字符串分割、strcat字符串拼接、strcpy、strcmp

代码 #define _CRT_SECURE_NO_WARNINGS#include <string.h> #include <stdio.h>char string[] "A string\tof ,,tokens\nand some more tokens"; char seps[] " ,\t\n"; char *token;int main(void) {printf("Tokens:\n");// Es…

电动机正反转继电器控制系统

微信公众号&#xff1a;创享日记 发送关键词&#xff1a;plc2 免费获取完整无水印实验报告 一、实验目的 1&#xff0e;学习和掌握电动机主回路的设计及接线&#xff1b; 2&#xff0e;学习和掌握电动机控制回路的设计及联锁保护方法&#xff1b; 3&#xff0e;加深对电气控制系…

电子技术课程设计-正弦波发生及频率显示电路-电子线路CAD原理图

微信公众号&#xff1a;创享日记 发送关键词&#xff1a;电子技术课设 免费获取完整无水印实验报告付费电子线路CAD原理图源文件及其导入教程 前些天发现了十分不错的人工智能学习电子书&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&a…

C语言实用算法系列之学生管理系统_对整个结构体操作_冒泡排序

代码 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <string.h> void Save();struct SUser // 结构体定义 {int nNumb; // 学号char sName[20]; // 姓名float fMath; // 数学成绩 }g_user[100];void Print() // 打印子函数 {puts("\n学号\t姓…

PLC 控制三相异步电动机正反转实验

前些天发现了十分不错的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&#xff0c;大家可以自行看看。&#xff08;点击跳转人工智能学习资料&#xff09; 微信公众号&#xff1a;创享日记 发送关键词&#xff1a;plc3…

功能Java示例 第4部分–首选不变性

这是称为“ Functional Java by Example”的系列文章的第4部分。 在上一部分中&#xff0c;我们讨论了一些副作用&#xff0c;并且我想进一步详细说明如何通过将不可变性引入代码中来防止以意外的方式操纵数据。 如果您是第一次来&#xff0c;最好是从头开始阅读。 它有助于…

C语言实用算法系列之学生管理系统_对整个结构体操作_选择排序_提取排序规则

代码 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <string.h> #include <stdlib.h> void Save();struct SUser {int nNumb;char sName[20];float fMath; }g_user[100];void Print() {puts("\n学号\t姓名\t数学");int i 0;while…

Altium Designer19(AD19)

微信公众号&#xff1a;创享日记 发送关键词&#xff1a;Altium 免费获取Altium Designer19 1、解压文件 2、解压后打开安装文件&#xff08;AD19 setup.exe&#xff09; 3、点击next 4、选择中文并接受协议 5、选择功能&#xff0c;Next 6、选择文件保存路径与安装路径&…

仿真proteus8.7安装

前些天发现了十分不错的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&#xff0c;大家可以自行看看。&#xff08;点击跳转人工智能学习资料&#xff09; 微信公众号&#xff1a;创享日记 发送关键词&#xff1a;prot…

C语言实用算法系列之学生管理系统_对整个结构体操作_冒泡排序_提取排序规则

代码 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <string.h> #include <stdlib.h> void Save();struct SUser {int nNumb;char sName[20];float fMath; }g_user[100];void Print() {puts("\n学号\t姓名\t数学");int i 0;while…

servlet 异常处理_Servlet异常和错误处理示例教程

servlet 异常处理有时候我写了一篇有关Java异常处理的文章&#xff0c;但是当涉及到Web应用程序时&#xff0c;我们需要的不仅仅是Java中的异常处理。 Servlet异常 如果您注意到&#xff0c;doGet&#xff08;&#xff09;和doPost&#xff08;&#xff09;方法将抛出ServletE…

基于51单片机直流电机PWM控制器设计

前些天发现了十分不错的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&#xff0c;大家可以自行看看。&#xff08;点击跳转人工智能学习资料&#xff09; 由STC89C52单片机、LCD1602液晶显示屏、霍尔测速传感器、3V直…

C语言实用算法系列之学生管理系统_单向链表内操作_选择排序

单向链表实现 #include <stdio.h> #include <malloc.h>typedef int DATA;struct SNode {DATA data;SNode* pNext; }; SNode* g_pHead NULL;void AddHead(DATA data) {SNode* p (SNode*)malloc(sizeof(SNode));p->data data;p->pNext g_pHead;g_pHead p…

如何从过滤器中排除URL

默认情况下&#xff0c;过滤器不支持排除特定的URL模式&#xff0c;每当您为过滤器定义URL模式时&#xff0c;任何与该模式匹配的请求都将由过滤器无例外处理。 从过滤器中排除URL的最简单方法是将过滤器映射到非常特定的模式。 在早期开发阶段完成此操作是可行的&#xff0c;…

大林算法控制仿真实验(计控实验六simulink)

前些天发现了十分不错的人工智能学习网站&#xff0c;通俗易懂&#xff0c;风趣幽默&#xff0c;没有广告&#xff0c;分享给大家&#xff0c;大家可以自行看看。&#xff08;点击跳转人工智能学习资料&#xff09; 微信公众号&#xff1a;创享日记 发送关键词&#xff1a;计控…

C语言实用算法系列之学生管理系统_单向链表内操作_提取排序规则

代码 后续文章的排序均采用速度较快的选择排序算法。 #define _CRT_SECURE_NO_WARNINGS#include <stdio.h> #include <string.h> #include <stdlib.h>enum {READ_ONLY,HIDE,SYSTEM 55,TEST };typedef struct SUser {int nNumb;char sName[20];float fMath…