zoukankan      html  css  js  c++  java
  • springmvc/springboot开发restful API, 使用MockMVC 编写测试用例

      非rest的url写法:

    查询  GET /user/query?name=tom
    详情  GET /user/getinfo?id=1
    创建  POST /user/create?name=tom
    修改  POST /user/update?id=1&name=tom
    删除  GET /user/delete?id=1

      rest风格的写法

    查询  GET /user?name=tom
    详情  GET /user/1
    创建  POST /user
    修改  PUT /user
    删除  DELETE /user/1

    rest接口设计参考:https://github.com/huobiapi/API_Docs/wiki/REST_api_reference

    https://github.com/huobiapi/API_Docs

    coinflext api: https://github.com/coinflex-exchange/API

    1、Rest概念,来自百度百科

      REST即表述性状态传递(英文:Representational State Transfer,简称REST)是Roy Fielding博士在2000年他的博士论文中提出来的一种软件架构风格。它是一种针对网络应用的设计和开发方式,可以降低开发的复杂性,提高系统的可伸缩性。

      目前在三种主流的Web服务实现方案中,因为REST模式的Web服务与复杂的SOAP和XML-RPC对比来讲明显的更加简洁,越来越多的web服务开始采用REST风格设计和实现。

      

    2、RESTful API的要求

      1)用URL描述资源;

      2)使用HTTP方法描述行为;使用HTTP状态码来表示不同的结果;

      3)使用json来交互数据;

      4)RESTful只是一种风格,并不是强制的标准。

      总结:使用URL定位资源,使用HTTP方法操作资源。

    GET     用来获取资源;
    POST    用来新建资源(也可以用于更新资源);
    PUT     用来更新资源;
    DELETE  用来删除资源

    3、Glory of REST

      REST是一种软件接口设计的模型。REST 成熟度模型:(搜索关键字:steps toward the glory of REST)

      

      level0: 使用http作为传输方式;

      level1: 引入资源概念,每个资源都有对应的URL;

      level2: 使用http方法进行不同的操作,使用http状态码来表示不同的结果。

      level3: 使用超媒体,在资源的表达中包含了链接信息。

    4、springmvc/springboot开发restful API

      IndexController

    @RestController
    public class IndexController {
        @Autowired
        private UserService userService;
        
        @GetMapping("/user/{id}")
        public Object getUserById(@PathVariable Integer id) {
            return userService.getUserById(id);
        }
    }

      测试结果:

    5、使用MockMVC 编写测试用例(单元测试)

      参考:https://www.cnblogs.com/xy-ouyang/p/10681965.html

      选中IndexController,右键/new/Junit Test Case

       测试用例代码:

    package com.imooc.controller;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.request.MockMvcRequestBuilders;
    import org.springframework.test.web.servlet.result.MockMvcResultHandlers;
    import org.springframework.test.web.servlet.result.MockMvcResultMatchers;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    /**
     * @author oy
     * @date 2019年6月22日 下午11:14:56
     * @version 1.0.0
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class IndexControllerTest {
    
        @Autowired
        private WebApplicationContext wac;
        
        private MockMvc mocMvc;
        
        @Before
        public void setUp() throws Exception {
            mocMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
    
        @Test
        public void testGetUserById() throws Exception {
            String mvcResult = mocMvc.perform(MockMvcRequestBuilders.get("/user/1")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED))
                    .andDo(MockMvcResultHandlers.print()) // 打印信息
                    .andExpect(MockMvcResultMatchers.status().isOk()) // 期望返回的状态码为200
                    .andExpect(MockMvcResultMatchers.jsonPath("$.length()").value(2)) // 期望返回的json数据中有两个字段
                    .andExpect(MockMvcResultMatchers.jsonPath("$.username").value("张三")) // 期望返回的json数据中username字段的值为"张三"
                    .andReturn().getResponse().getContentAsString();
        
            System.out.println("mvcResult: " + mvcResult);
        }
    }

       控制台打印结果:

    MockHttpServletRequest:
          HTTP Method = GET
          Request URI = /user/1
           Parameters = {}
              Headers = {Content-Type=[application/x-www-form-urlencoded]}
    
    Handler:
                 Type = com.imooc.controller.IndexController
               Method = public java.lang.Object com.imooc.controller.IndexController.getUserById(java.lang.Integer)
    
    Async:
        Async started = false
         Async result = null
    
    Resolved Exception:
                 Type = null
    
    ModelAndView:
            View name = null
                 View = null
                Model = null
    
    FlashMap:
           Attributes = null
    
    MockHttpServletResponse:
               Status = 200
        Error message = null
              Headers = {Content-Type=[application/json;charset=UTF-8]}
         Content type = application/json;charset=UTF-8
                 Body = {"username":"张三","password":"123"}
        Forwarded URL = null
       Redirected URL = null
              Cookies = []
    mvcResult: {"username":"张三","password":"123"}

      

      测试用例的代码简洁写法:使用静态导入

    package com.imooc.controller;
    
    import static org.springframework.test.web.servlet.request.MockMvcRequestBuilders.get;
    import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.jsonPath;
    import static org.springframework.test.web.servlet.result.MockMvcResultMatchers.status;
    
    import org.junit.Before;
    import org.junit.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.context.SpringBootTest;
    import org.springframework.http.MediaType;
    import org.springframework.test.context.junit4.SpringRunner;
    import org.springframework.test.web.servlet.MockMvc;
    import org.springframework.test.web.servlet.setup.MockMvcBuilders;
    import org.springframework.web.context.WebApplicationContext;
    
    /**
     * @author oy
     * @date 2019年6月22日 下午11:14:56
     * @version 1.0.0
     */
    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class IndexControllerTest {
    
        @Autowired
        private WebApplicationContext wac;
        
        private MockMvc mocMvc;
        
        @Before
        public void setUp() throws Exception {
            mocMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
    
        @Test
        public void testGetUserById() throws Exception {
            String mvcResult = mocMvc.perform(get("/user/1")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED))
                    .andDo(print()) // 打印信息
                    .andExpect(status().isOk()) // 期望返回的状态码为200
                    .andExpect(jsonPath("$.length()").value(2)) // 期望返回的json数据中有两个字段
                    .andExpect(jsonPath("$.username").value("张三"))
                    .andReturn().getResponse().getContentAsString();
        
            System.out.println("mvcResult: " + mvcResult);
        }
    }

    6、@PageableDefault指定默认的分页参数

       测试代码:

    @RunWith(SpringRunner.class)
    @SpringBootTest
    public class IndexControllerTest {
    
        @Autowired
        private WebApplicationContext wac;
        
        private MockMvc mocMvc;
        
        @Before
        public void setUp() throws Exception {
            mocMvc = MockMvcBuilders.webAppContextSetup(wac).build();
        }
    
        @Test
        public void testGetUserById() throws Exception {
            String mvcResult = mocMvc.perform(get("/user/1")
    //                .param("page", "2")
    //                .param("size", "10")
    //                .param("sort", "id,desc")
                    .contentType(MediaType.APPLICATION_FORM_URLENCODED))
                    .andDo(print()) // 打印信息
                    .andExpect(status().isOk()) // 期望返回的状态码为200
                    .andExpect(jsonPath("$.length()").value(2)) // 期望返回的json数据中有两个字段
                    .andExpect(jsonPath("$.username").value("张三"))
                    .andReturn().getResponse().getContentAsString();
        
            System.out.println("mvcResult: " + mvcResult);
        }
    }

      IndexController

    @RestController
    public class IndexController {
        @Autowired
        private UserService userService;
        
        @GetMapping("/user/{id}")
        public Object getUserById(@PathVariable Integer id, 
                @PageableDefault(page = 1, size = 10, sort = "id,asc") Pageable pageable) {
            
            String str = ReflectionToStringBuilder.toString(pageable, ToStringStyle.MULTI_LINE_STYLE);
            System.out.println(str);
            
            return userService.getUserById(id);
        }
    }

      控制台打印结果:

    org.springframework.data.domain.PageRequest@7d522180[
      sort=id,asc: ASC
      page=1
      size=10
    ]

    7、测试用例中jsonpath的用法

      github上面搜索jsonpath ==> https://github.com/json-path/JsonPath

      

    8、@PathVariable 以及url映射中使用正则表达式

    @GetMapping("/user/{id:\d+}")
    public Object getUserById(@PathVariable Integer id) {
        return userService.getUserById(id);
    }

      此时,请求url为 /user/a 时,报404。

    参考:

      1)详解REST架构风格:http://www.uml.org.cn/zjjs/201805142.asp

      2)REST,以及RESTful的讲解:https://blog.csdn.net/qq_21383435/article/details/80032375

      3) 阮一峰:RESTful API 设计指南

  • 相关阅读:
    brctl 使用说明
    Flash文件系统介绍和平台采用squashfs+ubifs原因
    xargs
    svn的常用命令
    shell中的if用法
    shell中单双引号
    删除文件中的 ^M 字符
    博客园添加live2d看板娘
    IOS 自定义转场动画
    rails
  • 原文地址:https://www.cnblogs.com/xy-ouyang/p/11070161.html
Copyright © 2011-2022 走看看