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

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

“集成测试”是指将Spring上下文加载到测试环境中,以便控制器可以在“端到端”测试中与合作者一起工作。

同样,我将从Spring Social Facebook项目中为FacebookPostsController编写一个测试,并且正如您所期望的那样,该测试将是我的FacebookPostsControllerTest类的集成测试版本。 如果需要查看FacebookPostsController代码或原始的FacebookPostsControllerTest代码,请查看我的上一个博客 。 有关FacebookPostsController代码的完整介绍,请参见Spring Social Facebook博客 。

创建集成测试的第一步是将Spring上下文加载到测试环境中。 这是通过在FacebookPostsControllerTest类中添加以下注释来完成的:

  1. @RunWith ( SpringJUnit4ClassRunner.class )
  2. @WebAppConfiguration
  3. @ContextConfiguration(“文件名”)
@RunWith(SpringJUnit4ClassRunner.class) 
@WebAppConfiguration 
@ContextConfiguration({ "file:src/main/webapp/WEB-INF/spring/appServlet/servlet-context.xml", "file:src/main/webapp/WEB-INF/spring/data.xml" }) 
public class FacebookPostsControllerTest {

@RunWith ( SpringJUnit4ClassRunner.class )或@ContextConfiguration(“ file-names”)并没有什么新意,因为它们从Spring 2.5开始就出现了,如果您是Spring开发人员,那么您之前可能已经在集成测试中使用过它们。 新人是@WebAppConfiguration 。

这些批注协同工作以配置您的测试环境。 @RunWith告诉JUnit使用Spring JUnit类运行器运行测试。 @WebAppConfiguration告诉SpringJUnit4ClassRunner集成测试要加载的ApplicationContext应该是WebApplicationContext ,而@ContextConfiguration用于指定加载哪个XML文件以及从何处加载。

在这种情况下,我正在加载项目的“ servlet-context.xml”和“ data.xml”文件。 “ servlet-context.xml”文件包含Spring Web应用程序所需的所有标准位,例如<annotation-driven />和视图解析器,而“ data.xml”则包含该应用程序的Spring Social组件。 这里要注意的一点是,我故意使用
我想运行端到端集成测试来访问文件系统,数据库等的伪生产配置文件。

这只是示例代码,在集成测试中通常不会涉及生产数据库或其他相关资源。 通常,您将配置您的应用程序以访问集成测试数据库和其他资源。 解决此问题的一种方法是创建一个测试 XML配置文件。 但是,不要像我在一个项目中看到的那样,为项目中的每个Maven模块创建单独的测试 XML文件。 原因是当您对代码进行更改时,最终要更改一大堆配置文件才能使集成测试再次正常工作,这既无聊又耗时。 更好的方法是拥有一个版本的XML配置,并使用Spring配置文件为不同的环境配置应用程序。 如果确实选择使用配置文件,则还需要将@ActiveProfiles(“profile-name”)批注添加到上面列出的其他三个批注中。 但是,这超出了本博客的范围。

假设您使用的是自动装配,并且您已经正确设置了<context:component-scan /> ,那么下一步就是将以下实例变量添加到测试类中:

@Autowired private WebApplicationContext wac;

这告诉Spring将先前创建的WebApplicationContext注入到测试中。 然后,可以在非常简单的一行setup()方法中使用它:

@Before public void setUp() throws Exception { mockMvc = MockMvcBuilders.webAppContextSetup(wac).build(); }

类似于此测试的“独立” /“编程”版本, setup()方法的目的是创建一个mockMvc实例,然后使用它来执行测试。 此处的区别在于,它只是通过使用WebApplicationContext作为MockMvcBuilders的参数来MockMvcBuilders

整理好setup()方法后,接下来要做的是编写一个测试,我将从上一个博客中重写testShowPostsForUser_user_is_not_signed_in()作为集成测试。 令人惊讶的是,该代码比以前的JUnit版本更简单:

@Test public void testShowPostsForUser_user_is_not_signed_in() throws Exception { ResultActions resultActions = mockMvc.perform(get("/posts").accept(MediaType.ALL)); resultActions.andExpect(status().isOk()); resultActions.andExpect(view().name("signin")); }

如果将此代码与我以前的博客中的testShowPostsForUser_user_is_not_signed_in()代码进行比较,您会发现它几乎相同。 唯一的区别是无需设置任何模拟对象。

在这一点上,我将演示testShowPostsForUser_user_is_signed_in测试的集成测试版本,但这确实有些棘手。 原因是要掌握他们的Facebook帖子列表,用户必须登录其Facebook帐户,这意味着在正确的必要HttpServletRequest对象之前,需要对服务器进行多次顺序调用状态以方便致电Facebook检索帖子列表。 对于示例代码来说,这似乎有点太复杂了,这是我不想在
真实的项目。

我不是将这种复杂性视为Spring MVC测试框架的局限性,而是要强调最佳实践,这是确保对服务器的调用尽可能独立且原子。

当然,我可以使用模拟对象或创建虚拟Facebook服务,但是,这超出了本博客的范围。

一个独立的一个很好的例子,原子服务器调用是REST调用testConfirmPurchases_selection_1_returns_a_hat(...)用于测试的OrderController从我采取类的Spring MVC,Ajax和JSON第2部分-服务器端代码博客。 此代码在Ajax博客中进行了全面描述,它请求购买确认,并以JSON的形式返回。

下面OrderController了返回JSON的OrderController代码:

/** * Create an order form for user confirmation */ @RequestMapping(value = "/confirm", method = RequestMethod.POST) public @ResponseBody OrderForm confirmPurchases(@ModelAttribute("userSelections") UserSelections userSelections) { logger.debug("Confirming purchases..."); OrderForm orderForm = createOrderForm(userSelections.getSelection()); return orderForm; } private OrderForm createOrderForm(List<String> selections) { List<Item> items = findItemsInCatalogue(selections); String purchaseId = getPurchaseId(); OrderForm orderForm = new OrderForm(items, purchaseId); return orderForm; } private List<Item> findItemsInCatalogue(List<String> selections) { List<Item> items = new ArrayList<Item>(); for (String selection : selections) { Item item = catalogue.findItem(Integer.valueOf(selection)); items.add(item); } return items; } private String getPurchaseId() { return UUID.randomUUID().toString(); }

尽管它返回的JSON看起来像这样:

{"items":[{"id":1,"description":"description","name":"name","price":1.00}, {"id":2,"description":"description2","name":"name2","price":2.00}],"purchaseId":"aabf118e-abe9-4b59-88d2-0b897796c8c0"}

下面以冗长的样式显示了测试testConfirmPurchases_selection_1_returns_a_hat(...)的代码。

@Test public void testConfirmPurchases_selection_1_returns_a_hat() throws Exception { final String mediaType = "application/json;charset=UTF-8"; MockHttpServletRequestBuilder postRequest = post("/confirm"); postRequest = postRequest.param("selection", "1"); ResultActions resultActions = mockMvc.perform(postRequest); resultActions.andDo(print()); resultActions.andExpect(content().contentType(mediaType)); resultActions.andExpect(status().isOk()); // See http://goessner.net/articles/JsonPath/ for more on JSONPath ResultMatcher pathMatcher = jsonPath("$items[0].description").value("A nice hat"); resultActions.andExpect(pathMatcher); }

上面的代码不是Spring Guys希望您编写的代码; 但是,以冗长的格式更容易讨论正在发生的事情。 该方法的结构类似于第1部分中讨论的testShowPostsForUser_user_is_signed_in(...)方法。第一步是使用静态MockMvcRequestBuilders.post(...)方法创建MockHttpServletRequestBuilder类型的postRequest对象。 值"1""selection"参数将添加到结果对象中。

然后将postRequest传递给mockMvc.perform(...)方法,并返回一个ResultActions对象。

然后使用andExpect(...)方法验证ResultActions对象,以检查HTTP状态(ok = 200)和内容类型为"application/json;charset=UTF-8"

此外,我还添加了一个andDo(print())方法调用,以显示HttpServletRequestHttpServletResponse对象的状态。 该调用的输出如下所示:

MockHttpServletRequest:HTTP Method = POSTRequest URI = /confirmParameters = {selection=[1]}Headers = {}Handler:Type = com.captaindebug.store.OrderControllerMethod = public com.captaindebug.store.beans.OrderForm com.captaindebug.store.OrderController.confirmPurchases(com.captaindebug.store.beans.UserSelections)Resolved Exception:Type = nullModelAndView:View name = nullView = nullModel = nullFlashMap:MockHttpServletResponse:Status = 200Error message = nullHeaders = {Content-Type=[application/json;charset=UTF-8]}Content type = application/json;charset=UTF-8Body = {"items":[{"id":1,"description":"A nice hat","name":"Hat","price":12.34}],"purchaseId":"d1d0eba6-51fa-415f-ac4e-8fa2eaeaaba9"}Forwarded URL = nullRedirected URL = nullCookies = []

最后一项测试使用静态MockMvcResultMatchers.jsonPath(...)检查"$items[0].description"的JSON路径的值是否为"A nice hat" 。 为了使用jsonPath(...)静态方法,您必须在POM.xml中包含JSON Path模块以解析JSON。

<dependency><groupId>com.jayway.jsonpath</groupId><artifactId>json-path</artifactId><version>0.8.1</version><scope>test</scope></dependency>

JSonPath是一种从JSon数据中选择性提取字段的方法。 它基于XML的XPath思想。

显然,我上面用过的冗长风格不需要编写测试。 下面的代码显示与Spring的Guy设计的相同代码:

@Test public void testConfirmPurchases_spring_style() throws Exception { mockMvc.perform(post("/confirm").param("selection", "1")).andDo(print()) .andExpect(content().contentType("application/json;charset=UTF-8")) .andExpect(status().isOk()) .andExpect(jsonPath("$items[0].description").value("A nice hat")); }

所以,仅此而已。 概括地说,我们的想法是向您的单元测试中添加适当的注释,以便Spring加载您的XML配置以创建WebApplicationContext 。 然后将其注入到您的测试中,并在创建mockMvc时作为参数传递给Spring MVC Test框架。 然后编写测试,其想法是将适当构造的MockMvcRequestBuilders对象传递给mockMvc.perform(...)方法,然后将其返回值声明为通过或失败测试。

该博客的代码可在GitHub上找到: https : //github.com/roghughe/captaindebug/在Facebook和Ajax-JSON项目中。

参考: Spring的MVC测试框架入门–第2部分,来自我们的JCG合作伙伴 Roger Hughes,来自Captain Debug的Blog博客。

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

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

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

相关文章

jira java接口生成问题

参考页面: 可方便扩展的JIRA Rest Web API的封装调用 JIRA是一个缺陷跟踪管理系统&#xff0c;被广泛应用于缺陷跟踪、客户服务、需求收集、流程审批、任务跟踪、项目跟踪和敏捷管理等工作领域,当我们需要把第三方业务系统集成进来时&#xff0c;可以调用他的API。 JIRA本身的A…

pmd 使用笔记

pmd是一块开源的代码静态分析工具&#xff0c;使用java编写&#xff0c;可以自定义规则来进行自己想要的分析。pmd可以单独使用&#xff0c;也可以作为idea、eclipse的插件使用。它的规则分为xpath规则&#xff0c;和java规则。https://pmd.github.io/ pmd内部工作机制比较简单…

css用一张大图片来设置背景的技术真相

之前就知道了用一张图片来设置页面内的所有背景的技术。原理很简单&#xff0c;利用background-potision精确地定位到图片的位置。好处是减少页面 的http请求数。 老实说&#xff0c;我并不觉得这个技术有多值得推广。虽然是减少了http请求数&#xff0c;但对于99%的网站来说&…

flex 平铺布局_flex布局及各种布局的总结

Flexbox display: flex;如果也想设置内联元素为弹性盒子&#xff0c;可以使用display:inline-flex;实现三种其他布局难以达到的效果&#xff1a;在父内容里面垂直居中一个块内容。使容器的所有子项占用等量的可用宽度/高度&#xff0c;而不管有多少宽度/高度可用。使多列布局中…

计算机网络应用押韵句,现代汉语练习题

第一章导论一、填空题1、汉语做为一种语言&#xff0c;具有一切语言共有的性质。即从内部结构上说&#xff0c;它是一种音译结合的符号系统&#xff1b;从外部功能上说&#xff0c;它是人类社会重要的交际工具和思维工具。2、语言符号最重要的特点是任意性和线条性。3、“现代汉…

Python中 sys.argv[]的用法简明解释

Python中 sys.argv[]的用法简明解释 因为是看书自学的python,开始后不久就遇到了这个引入的模块函数&#xff0c;且一直在IDLE上编辑了后运行&#xff0c;试图从结果发现它的用途&#xff0c;然而结果一直都是没结果&#xff0c;也在网上查了许多&#xff0c;但发现这个问题的比…

在Apache Hadoop(多节点群集)中运行Map-Reduce作业

我们将在这里描述在多节点集群中的Apache Hadoop中运行MapReduce Job的过程。 要在多节点群集中设置Apache Hadoop &#xff0c;可以阅读设置Apache Hadoop多节点群集 。 为了进行设置&#xff0c;我们必须在每台计算机上使用以下配置Hadoop&#xff1a; 在所有节点的conf / …

写出完美CSS代码的5个重要方面

每个人都可以编写CSS代码&#xff0c;甚至你现在已经让它为你的项目工作了。我在博客中也一直与大家讨论&#xff0c;学习CSS编码与CSS技巧。但是CSS还 可以更好吗&#xff1f;开始用这5个Tips改进你的CSS吧&#xff01; 一、关于 CSS重置 首先&#xff0c;很认真的告诉你&…

文件上传漏洞及其绕过、对策、过狗

1. 文件包含上传&#xff1a; php://input属于php内置的封装协议&#xff0c;其实都主要是include&#xff08;&#xff09;函数处理不当如果有文件是以下写法&#xff0c;xxx随便&#xff1a;<?phpinclude($_GET[xxx]);?> 以上保存到test.php&#xff0c; 我们访问ht…

一维二维_更高效的一维、二维材料过渡态搜索

前言本文中&#xff0c;我们首先介绍如何使用NEB方法搜索过渡态&#xff0c;以及在NEB的结果的基础上&#xff0c;进一步提高精度优化出高精度、可验证的过渡态。本文以MoS2的一维条带(其中一个Mo原子被Co替代掺杂)为例进行演示。一般来说&#xff0c;这种反应&#xff0c;周期…

2013年测试基于Web的Spring应用程序(第1部分)

2013年测试基于Web的Spring应用程序&#xff08;第1部分&#xff09; LJCer和TDD / BDD的一位拥护者最近开始使用广受欢迎的Spring堆栈开发应用程序&#xff0c;他就如何最好地在这种情况下实施测试驱动的方法向我提出了建议。 我开始回覆一封电子邮件作为回应&#xff0c;但后…

计算机类课程嵌入式系统的特点及其应用,嵌入式系统的准确定义、特点及其重要性...

嵌入式计算机系统的出现&#xff0c;是现代计算机发展史上的里程碑事件。嵌入式系统诞生于微型计算机时代&#xff0c;与通用计算机的发展道路完全不同&#xff0c;形成了独立的单芯片的技术发展道路。由于嵌入式系统的诞生&#xff0c;现代计算机领域中出现了通用计算机与嵌入…

【Linux】cp命令

用途 cp除了复制功能之外还可以建立快捷方式 全称 cp的全称为copy 参数 -a :相当于同时指定参数pdr -d :若文件为链接文件的属性(link file),则复制链接文件属性而非档案本身 -f &#xff1a;强制的意思(force)&#xff0c;若目标档案已经存在且无法开启&#xff0c;则移除后再…

网页变成灰色,对重大事件表示哀悼

body * { -webkit-filter: grayscale(100%); -moz-filter: grayscale(100%); -ms-filter: grayscale(100%); -o-filter: grayscale(100%); filter: grayscale(100%); filter:progid:DXImageTransform.Microsoft.BasicImage(grayscale1); filter: gray; } 兼容所有浏览器&#x…

Mybatis之逆向工程

前面几篇基本把mybatis简单使用学习了下,今天学习下mybatis逆向工程&#xff0c;我们在开发中经常需要先设计数据库表结构或者先设计model,那就是能不能有工具可以只需在一边设计之后另一边自动生成呢&#xff1f;于是逆向工程来了。这里的逆向功能是通过数据库的表生成java po…

2023航天推进理论基础考试划重点(W老师)-液体火箭发动机1

适用于期末周求生欲满满的西北工业大学学生。 1、液体火箭发动机的基本组成及功能是什么&#xff1f; 推力室组件、推进剂供应系统、阀门与调节器、发动机总装元件等组成。 2、液体火箭发动机的分类和应用是什么&#xff1f;3、液体火箭发动机系统、分系统的概念是什么&…

minio 并发数_c#(asp.net)线程配置总结

本文为大家介绍有关c#(asp.net)线程配置的相关知识&#xff0c;有需要的朋友可以参考下。同一时刻只能发起的工作线程数量。1、(maxWorkerThreads * CPU逻辑数量)-minFreeThreads比如2个CPU默认配置maxWorkerThreads100&#xff0c;minFreeThreads176&#xff0c;则同时最大只能…

Java EE 7是最终版本。 思想,见解和进一步的指针。

我们花了不到三年的时间才推出了下一个Java EE版本 。 今年4月16日&#xff0c; JCP EC对JSR 342进行了投票并获得批准。 这是一个成功的故事&#xff0c;因为在去年八月下旬的最后时刻撤消了拥有云就绪平台的最初想法。 作为EG的成员&#xff0c;撰写即将发布的功能或多或少容…

远程教育英语和计算机没过怎么办,网络教育英语统考能考几次 没考过怎么办?...

网络教育英语统考能考几次?网络教育统考是可以在学制期限内多次报考&#xff0c;直到考试合格为止。不过从2018年4月统考开始&#xff0c;所有考生只要一次弃考&#xff0c;弃考科目就只能再有3次报考机会(含以后的弃考)。网络教育统考每年有三次考试时间&#xff0c;分别是4、…

JavaScript的arguments及其子对象

首先一个最大的问题是&#xff0c;arguments这个对象哪儿来的&#xff1f;也许有人会认为它是调用函数时引擎自带的一个局部变量&#xff0c;因为我们平时使用arguments的时候都是在函数中把它当作局部变量来使用的。事实上arguments是Function实例的属性&#xff0c;只是在调用…