在很多Java企业级应用中,Spring占据了非常重要的位置,这就导致了基本上的技术选型都是围绕着Spring来, 比方说笔者最近的项目需要开发一个Restful的API接口,选型的时候就说,客户架构师直接就拍了spring-ws,原因呢?系统中其他的模块都是用的Spring-ws,保持一致,而且社区活跃,文档丰富,遇到问题易解决。好了,入正题。


既然选定了Spring-WS, 已经TDD入魔的我,首先想到的就是我应该怎么测试这个API接口呢? 作为业界最成熟的框架,Spring为测试其Web应用提供了非常好用的辅助类MockMvc。



首先,在项目的测试代码中加入辅助Spring Web测试的库

  1. testCompile(
  2. "org.springframework:spring-test:$springVersion",
  3. "org.springframework.ws:spring-ws-test:2.1.0.RELEASE",
  4. "javax.servlet:javax.servlet-api:3.0.1",
  5. "com.jayway.jsonpath:json-path-assert:0.9.0"
  6. )

其中,jsonpath库的依赖是为了更好的做json格式数据的断言。



然后,编写测试代码

  1. //指定使用SpringIntegration测试,并且制定了运行测试的ApplicationContext
  2. @RunWith(SpringJUnit4ClassRunner.class)
  3. @ContextConfiguration(locations = {"classpath:spring-servlet.xml"})
  4. public class ApiControllerIntegrationTest {
  5. @Autowired
  6. private ApiController controller;
  7. private MockMvc mockMvc;
  8. @Before
  9. public void setUp() throws Exception {
  10. //绑定需要测试的Controller到MockMvcshang
  11. mockMvc = MockMvcBuilders.standaloneSetup(controller).build();
  12. }
  13. @Test
  14. public void testGet() throws Exception {
  15. //发出请求,在请求中可以设置一个http request可设置的所有参数
  16. mockMvc.perform(get("/requests/1")
  17. .contentType(MediaType.APPLICATION_JSON)
  18. .accept(MediaType.APPLICATION_JSON)
  19. .param("userId", "xianlinbox")
  20. )
  21. //验证Respondse,status()中,可验证所有的HTTP Status CODE
  22. //另外,使用了jsonPath更优雅的做json属性值的验证
  23. .andExpect(status().isOk())
  24. .andExpect(jsonPath("$.userId").value("xianlinbox"))
  25. .andExpect(jsonPath("$.requestId").value("1"))
  26. .andExpect(jsonPath("$.requestType").value("GET"));
  27. }
  28. @Test
  29. public void testPost() throws Exception {
  30. mockMvc.perform(post("/requests")
  31. .contentType(MediaType.APPLICATION_JSON)
  32. .accept(MediaType.APPLICATION_JSON)
  33. .content("this is the message")
  34. .param("userId", "xianlinbox")
  35. )
  36. //使用print()可打印出当前测试设计的HTTP Request/Responsed的所有信息,方便定位问题
  37. //Post方法的返回结果应该是202(HttpStatus.Created),对象创建成功
  38. .andDo(print())
  39. .andExpect(status().isCreated())
  40. .andExpect(jsonPath("$.userId").value("xianlinbox"))
  41. .andExpect(jsonPath("$.requestType").value("POST"))
  42. .andExpect(jsonPath("$.message").value("this is the message"));
  43. }
  44. }

testPost方法中的print()语句打印出的效果如下:

MockHttpServletRequest:

         HTTP Method = POST

         Request URI = /requests

          Parameters = {userId=[xianlinbox]}

             Headers = {Content-Type=[application/json], Accept=[application/json]}



             Handler:

                Type = com.xianlinbox.api.ApiController

              Method = public com.xianlinbox.api.Request
com.xianlinbox.api.ApiController.post(java.lang.String,java.lang.String)



               Async:

   Was async started = false

        Async result = null



  Resolved Exception:

                Type = null



        ModelAndView:

           View name = null

                View = null

               Model = null



            FlashMap:



MockHttpServletResponse:

              Status = 201

       Error message = null

             Headers = {Content-Type=[application/json;charset=UTF-8]}

        Content type = application/json;charset=UTF-8

                Body = {"userId":"xianlinbox","requestId":"1","requestType":"POST","message":"this is the message"}

       Forwarded URL = null

      Redirected URL = null

             Cookies = []



看完了测试, 来简单的看下具体的实现代码:

  1. @Controller
  2. public class ApiController {
  3. @RequestMapping(value = "/requests/{requestId}", method = RequestMethod.GET)
  4. @ResponseBody
  5. public Request get(@PathVariable String requestId, @RequestParam(value = "userId") String userId) {
  6. return new Request(userId, requestId, "GET");
  7. }
  8. @RequestMapping(value = "/requests", method = RequestMethod.POST)
  9. @ResponseBody
  10. @ResponseStatus(value = HttpStatus.CREATED)
  11. public Request post(@RequestParam(value = "userId") String userId, @RequestBody String content) {
  12. Request request = new Request(userId, "1", "POST");
  13. request.setMessage(content);
  14. return request;
  15. }
  16. }
  • 使用RequestMapping定义URL
  • 使用@ResponseBody表示返回json
  • 使用@PathVariable 获取路径参数
  • 使用@RequestParam获取request payload中的参数
  • 使用@RequestBody获取request body
  • 使用@ResponseStatus(value = HttpStatus.CREATED),定义返回的HTTP STATUS CODE

该Demo的所有代码: https://github.com/xianlinbox/TDD_Demo/tree/master/spring-ws-rest

基于Spring-WS的Restful API的集成测试的更多相关文章

  1. 基于Spring Boot的RESTful API实践(一)

    1. RESTful简述    REST是一种设计风格,是一组约束条件及原则,而遵循REST风格的架构就称为RESTful架构,资源是RESTful的核心,一个好的RESTful架构,通过URL就能很 ...

  2. 使用Spring MVC开发RESTful API

    第3章 使用Spring MVC开发RESTful API Restful简介 第一印象 左侧是传统写法,右侧是RESTful写法 用url描述资源,而不是行为 用http方法描述行为,使用http状 ...

  3. 使用 node-odata 轻松创建基于 OData 协议的 RESTful API

    前言 OData, 相信身为.NET程序员应该不为陌生, 对于他的实现, 之前也有童鞋进行过介绍(见:这里1,这里2). 微软的WCF Data Service即采用的该协议来进行通信, ASP.NE ...

  4. spring jwt springboot RESTful API认证方式

    RESTful API认证方式 一般来讲,对于RESTful API都会有认证(Authentication)和授权(Authorization)过程,保证API的安全性. Authenticatio ...

  5. Spring Boot构建RESTful API与单元测试

    如果您对Spring MVC不熟悉并且还没有尝试过快速入门案例,建议先看一下相关的内容. @Controller:修饰class,用来创建处理http请求的对象 @RestController:Spr ...

  6. 使用 Spring Boot 构建 RESTful API

    1. 使用 Idea 创建 Spring Initializer 项目 在创建项目的对话框中添加 Web 和 Lombok,或者建立项目后在 pom.xml 中添加依赖: <dependency ...

  7. Spring Boot中Restful Api的异常统一处理

    我们在用Spring Boot去向前端提供Restful Api接口时,经常会遇到接口处理异常的情况,产生异常的可能原因是参数错误,空指针异常,SQL执行错误等等. 当发生这些异常时,Spring B ...

  8. Spring Boot构建RESTful API

    @Controller:修饰class,用来创建处理http请求的对象 @RestController:Spring4之后加入的注解,原来在@Controller中返回json需要@ResponseB ...

  9. 用Kotlin写一个基于Spring Boot的RESTful服务

    Spring太复杂了,配置这个东西简直就是浪费生命.尤其在没有什么并发压力,随便搞一个RESTful服务 让整个业务跑起来先的情况下,更是么有必要纠结在一堆的XML配置上.显然这么想的人是很多的,于是 ...

随机推荐

  1. C++中的Traits技法

    Traits广泛应用于标准程序库.Traits classes使得"类型相关信息"在编译期可用. 认真读完下面的示例,你应该就懂了Traits技法,其实并不难. #include ...

  2. apache 运行php环境之困扰,无法加载多个不同的.html文件

    又是一个项目,为多个纯静态html页面h5游戏页,原本是一个简单得不能的项目,但是却多生了事端. 我按照apache的惯例,将文件上传到服务器的DocumentRoot目录,进行测试了. 刚开始使用目 ...

  3. 真分布式SolrCloud+Zookeeper+tomcat搭建、索引Mysql数据库、IK中文分词器配置以及web项目中solr的应用(1)

    版权声明:本文为博主原创文章,转载请注明本文地址.http://www.cnblogs.com/o0Iris0o/p/5813856.html 内容介绍: 真分布式SolrCloud+Zookeepe ...

  4. SQL 数据库基本知识

    SQL:Structured Quety Language SQL SERVER是一个以客户/服务器(c/s)模式访问.使用Transact-SQL语言的关系型数据库管理子系统(RDBMS) DBMS ...

  5. 内功心法 -- Java中的深拷贝和浅拷贝

    写在前面的话:读书破万卷,编码如有神--------------------------------------------------------------------这篇博客主要来谈谈" ...

  6. UltraEdit的配置

    这两天看同学门写的博客,很多人都是些的配置文件如何配置,看完以后感觉获益很大啊,从dos中不在需要输入javac.exe文件的地址就可以访问到javac的文件,为我们的java的编译提供了很大的帮助. ...

  7. iOS RunTime你知道了总得用一下

    说点题外话: 我刚来现在这家公司的时候,老板让我下载一个脉脉,上去找找自己的同行,多认识些同行.其实初衷的好的,但最近这两天我把它卸载了,不为别的,负能量太多!iOS这行自从2016就没景气过,在这行 ...

  8. python报错UnicodeDecodeError: 'ascii' codec can't decode byte 0xe8 in position 0 解决方案

    环境:mac+python 2.7 场景描述:在使用python修改excel内容修改表格内容为中文保存时报以下错误 此时已经设置了utf-8了 但保存时仍然报错错 此时将python中的中文使用un ...

  9. Visual Studio 2017 离线安装方式

    Visual Studio, 特别是Visual Studio 2017 通常是一个在线安装程序,如果你在安装过程中失去连接,你可以遇到问题.但是,由于法律原因,微软没有提供完整的可下载的ISO镜像. ...

  10. 浅谈Activiti Modeler 的扩展

    为什么要扩展         最近项目打算用activiti工作流中activiti modeler来做模块的可视化订阅,但是原生的activiti任务节点,有一些不符合业务需要,比如 配置项多,属性 ...