spring-boot-接口测试

Spring-boot中接口测试方法

1.swagger->springMVC(适用于单元测试)

为什么要使用swagger

  1. 就是我们在平时做项目时 如果接口太多?难道要自己一个一个去记吗?有没有什么测试方法可以优化测试api接口

swagger的优缺点:

​ Springboot中 swagger2 帮我们解决这个问题 swagger2 提供一个可视化界面,解决了我们要去记接口路径的麻烦

​ 缺点:1.在开发中需要去写很多参数和方法的描述,

​ 2. 同时这个不安全,会将自己项目信息暴露出来,上线时一定要屏蔽这个访问网址(或者在控制类上使用@ConditionalOnProperty(value = “false”)来决定是否显示该控制类的接口方法)

注解说明(在代码中解释)

  1. 引入依赖
<dependency>
<groupId>io.springfox</groupId>
<artifactId>springfox-boot-starter</artifactId>
<version>3.0.0</version>
</dependency>

​ 因为我们这里用的是3.0版本所以不需要通过@EnableSwagger2启动

  1. 控制类

    package com.y.controller;

    import com.y.Pojo.ResUser;
    import com.y.biz.ResuserBiz;
    import io.swagger.annotations.*;
    import lombok.extern.slf4j.Slf4j;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.web.bind.annotation.RequestMapping;
    import org.springframework.web.bind.annotation.RequestMethod;
    import org.springframework.web.bind.annotation.RequestParam;
    import org.springframework.web.bind.annotation.RestController;

    @RestController
    @Slf4j
    @RequestMapping("/user")
    @Api(value = "UserController",tags = "用户接口")//@Api:资源描述 tags:字符串;标签(也可理解成分类),会替换 Controller 名称;
    public class UserController {
    @Autowired
    private ResuserBiz resuserBiz;
    @ApiOperation("根据用户名和密码查用户") //@ApiOperation:方法描述
    @RequestMapping(value = "/findUserByUsernameAndPwd",method = RequestMethod.POST)
    @ApiImplicitParams({
    @ApiImplicitParam(name = "username", value = "用户名"),
    @ApiImplicitParam(name = "pwd",value = "密码")//@ApiImplicitParam(s):参数描述
    // 参数描述,可用在方法头。
    })
    @ApiResponses({
    @ApiResponse(code = 200, message = "成功,返回数据"),//可以根据状态码返回提示信息
    @ApiResponse(code = 1000, message = "失败")
    })
    public String login(@ApiParam("用户名") @RequestParam String username,//@ApiParam:参数描述
    // 参数描述,用在每个参数前面
    @ApiParam("用户密码") @RequestParam String pwd){
    ResUser resUser = resuserBiz.findByName(username, pwd);
    if (resUser!=null){
    return "欢迎你"+resUser.getUsername();
    }
    return "账号或密码错误";
    }
    }

​ 代码中@ApiImplicitParams和@ApiParam的区别

	关于 @ApiImplicitParam 和 @ApiParm 它俩都能为方法的请求参数做注释,区别有:
@ApiImplicitParam 可以在方法前使用,而 @ApiParm 只能在参数前使用
@ApiImplicitParam 提供的可设置属性更多,特别是 paramType 很关键
对于 @RequestBody 标识的 Json 字符串,不能使用 @ApiImplicitParam,会出现无法识别的情况
通过 @ApiParm 对 @RequestBody 的参数进行说明
另外,两者是可以混搭使用的,一般推荐使用 @ApiImplicitParam(s),但是注意 @RequestBody 的情况。

使用可视化界面

swagger2可视化界面的地址 http://localhost:9000/swagger-ui/index.html#/ (这里的9000是启动项目的端口号)

image-20231022161209827

这是响应体,其中200,和1000是我们刚刚自己设置的

image-20231022161527445

我们测试时只要点击对应的try it out即可

image-20231022161754464

2.用postman这样类似的软件测试(可以写脚本,这里不做演示)

3.集成测试 mock 模拟web请求

1.Mock Mvc是什么

Spring MVC 测试框架,也称为 MockMvc,为测试 Spring 提供支持。它执行完整的Spring MVC请求处理,MockMvc 可以单独用于执行请求和验证响y应mockMvc复制完整的 Spring MVC 请求处理,而无需启动服务器。 同时它也可以是通过WebTestClient使用,其中MockMvc作为服务器来处理请求的优点是选择使用更高级别的对象而不是原始数据,以及切换到完整的端到端HTTP的能力 针对实时服务器进行测试并使用相同的测试 API。

2.如何使用

  1. 在pom文件中导入对应依赖

    <dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-test</artifactId>
    </dependency>
  2. 创建Test对象

在你要测试的控制类右击鼠标->goto->Test->Create New Test->选择要测试的方法->OK

img

image-20231022193028202

它会自动给你构建当前控制类所在的相同的包结构 列如:

image-20231022192728262

  1. 在构建出来的测试类中编写测试代码

    package com.y.controller;

    import com.y.Pojo.Resfood;
    import com.y.ResApp;
    import org.hamcrest.Matchers;
    import org.junit.jupiter.api.DisplayName;
    import org.junit.jupiter.api.Test;
    import org.junit.runner.RunWith;
    import org.springframework.beans.factory.annotation.Autowired;
    import org.springframework.boot.test.autoconfigure.web.servlet.AutoConfigureMockMvc;
    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.MockMvcResultMatchers;

    import static org.springframework.test.web.servlet.result.MockMvcResultHandlers.print;

    @RunWith(SpringRunner.class)
    @SpringBootTest(classes = {ResApp.class},
    //在每一次mock测试时用随机端口启动,避免多个测试用例同时启动时产生端口占用的问题
    webEnvironment = SpringBootTest.WebEnvironment.RANDOM_PORT
    )
    @AutoConfigureMockMvc(addFilters = false)//自动配置和启用MockMvc配置 如果不加这个注解 下面是不能注入的

    class FoodControllerTest {
    @Autowired
    private MockMvc mockMvc;
    //预期对象
    Resfood resfood=new Resfood(1,"板栗鸭","22.00","20.00","营养丰富","500008.jpg");

    @Test
    @DisplayName("文本响应测试用例")
    void findById() {
    //使用注入的mockMvc模拟发送请求
    //MockMvcRequestBuilders:请求构造器
    try{
    //在请求后面还可以指定请求类型
    mockMvc.perform(MockMvcRequestBuilders.get("/food/findByFid")
    .contentType(MediaType.APPLICATION_JSON_VALUE)
    .param("fid","1")//拼接在请求路劲之后
    )
    //MockMvcResultMatchers:mockMvc结果匹配器
    .andExpect(MockMvcResultMatchers.status().isOk())//列如当前为匹配状态码为200或者其他表示成功
    //用于返回body
    .andExpect(MockMvcResultMatchers.jsonPath("$.data.fname", Matchers.equalToIgnoringCase(resfood.getFname())))
    //如果状态码符合预期,则进行print输出响应信息
    .andDo(print())
    //真正请求得到的响应的内容,真正执行的返回值
    .andReturn();
    } catch (Exception e) {
    throw new RuntimeException(e);
    }
    }

    3.代码解释

    image-20231022193958003

    1. MockMvcRequestBuilders.get(“/food/findByFid”) 用来构造一个请求(我这里是get请求)

    2. 接口MockMvcBuilder,提供一个唯一的build方法,用来构造MockMvc

    3. .andExpect添加执行完成后的断言其中$.data.fname 是返回数据中的属性(来判断是不是我期望的数据)image-20231022194429117

    4. andDo添加一个结果处理器,表示要对结果做点什么事情,比如此处使用print()输出整个响应结果信息。(下图为一部分)

    image-20231022195054720

    1. .andReturn表示执行完成后返回相应的结果。

​ 更详细内容详见->MockMvc :: Spring Framework