Swagger测试

关于Swagger

QQ截图20231022200152

Swagger 简介

Swagger 是一个用于设计、构建、文档化和使用 Restful API 的开源框架。它提供了一组工具,包括用于创建 API 规范的 Swagger 编辑器、用于生成 API 客户端代码的 Swagger Codegen,以及用于 API 文档化和测试的 Swagger UI。

Swagger 的主要目标是简化开发者在构建 API 时的工作流程,并促进不同团队之间的协作。通过使用 Swagger,开发者可以使用简单的 YAML 或 JSON 文件定义 API 的端点、参数、请求和响应体,并基于这些定义生成文档和代码。这样,开发者可以更好地定义 API 的结构和行为,同时也可以为开发者、测试人员和客户提供一个易于理解和使用的接口文档。

除了 API 定义和文档生成外,Swagger 还提供了一些工具和插件,以帮助开发者自动生成客户端代码、执行自动化测试以及部署和管理 API。

Swagger UI

Swagger UI 是 Swagger 的一个组件,用于可视化展示和交互式测试 API 的文档。它基于 Swagger 规范生成一个漂亮和功能丰富的用户界面,让开发者能够更好地理解和使用 API。

使用 Swagger UI,开发者可以直接在浏览器中查看 API 的所有细节,包括端点、请求和响应的参数、数据类型、示例和说明等。Swagger UI 提供了一个交互式的界面,可以方便地构建和发送请求,并查看返回的结果。它还支持代码片段的自动生成,帮助开发者快速集成 API 到他们的应用程序中。

Swagger UI 的界面简洁明了,页面左侧是 API 的目录结构,右侧则是选中端点后的详细信息,包括请求参数、响应示例和状态码等。用户可以直接在界面上填写参数并发送请求,在页面上获得实时的响应结果。此外,Swagger UI 还支持测试用例的导入和导出,方便与团队成员共享和合作。

总结来说,Swagger UI 是一个强大的工具,可用于呈现和测试 API 的文档。它提供了一个直观且易于使用的界面,可以帮助开发者更好地理解、交互和测试他们的 API。

swagger测试的缺点

1.过于繁多的注解给后续的代码维护带来了许多麻烦,如果代码内容发生的变化,注解对应描述内容也要进行修改,如果未及时修改,会造成文档内容不准确,给后续代码的修改带来了许多麻烦.

2.安全性问题,对于一个网站,该测试方法只需在Web地址后加上swagger-ui.html就可以访问到swagger的后台,可以对代码核心内容进行测试查询,将数据库关键信息暴露出来,不利于数据的保护;

3.运行时性能开销:Swagger 2 的生成过程需要读取和解析源代码,这可能会引入一些运行时的性能开销。尤其是在大型项目中,这可能会对性能产生一定的影响。

Swagger 快速开始

配置pom.xml,引入依赖

1
2
3
4
5
<dependency>
<groupId>com.spring4all</groupId>
<artifactId>swagger-spring-boot-starter</artifactId>
<version>1.9.0.RELEASE</version>
</dependency>

提供的业务场景

1
模拟实现一个订餐系统,通过菜品的Id查菜品有关的信息

entity

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
package com.yc.bean;

import com.baomidou.mybatisplus.annotation.IdType;
import com.baomidou.mybatisplus.annotation.TableId;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;

import java.io.Serializable;

@Data
@NoArgsConstructor
@AllArgsConstructor
public class Resfood implements Serializable {
@TableId(type = IdType.AUTO)
private Integer fid;
private String fname;
private Double normprice;
private Double realprice;
private String detail;
private String fphoto;
}

service层

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.yc.biz;

import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.yc.bean.Resfood;
import java.util.List;

public interface ResFoodBiz {

//通过菜品的id查询菜品信息
public Resfood findById(Integer fid);

}

Mapper层

1
2
3
4
5
6
7
8
9
package com.yc.dao;

import com.baomidou.mybatisplus.core.mapper.BaseMapper;
import com.yc.bean.Resfood;

public interface ResFoodMapper extends BaseMapper<Resfood> {
//利用动态代理根据这个接口的方法啊来生成一个代理对象,并将所有的方法实现
}

ServiceImpl

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
package com.yc.biz;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.yc.bean.Resfood;
import com.yc.dao.ResFoodMapper;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

@Service
public class ResFoodBizImpl implements ResFoodBiz{

@Autowired
private ResFoodMapper resFoodMapper;

@Override
public Resfood findById(Integer fid) {
QueryWrapper wrapper = new QueryWrapper();
wrapper.eq("fid",fid);
Resfood resfood = resFoodMapper.selectOne(wrapper);
return resfood;
}





}

Contrller层

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
package com.yc.controller;

import com.yc.bean.Resfood;
import com.yc.biz.ResFoodBiz;
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.RequestParam;
import org.springframework.web.bind.annotation.RestController;

import java.util.List;

@RestController
@RequestMapping("/resfood")
@Slf4j//生成日志
public class ResFoodController {

@Autowired
private ResFoodBiz resFoodBiz;

@RequestMapping("/findById")
public Resfood findById(@RequestParam Integer fid){
Resfood resfood = resFoodBiz.findById(fid);
return resfood;
}



}

启动类

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
package com.yc;

import org.mybatis.spring.annotation.MapperScan;
import org.springframework.boot.SpringApplication;
import org.springframework.boot.autoconfigure.SpringBootApplication;
import springfox.documentation.swagger2.annotations.EnableSwagger2;

@SpringBootApplication
@EnableSwagger2 //开启seagger注解驱动
@MapperScan("com.yc.dao")
public class ResApp {
public static void main(String[] args) {
SpringApplication.run(ResApp.class,args);
}
}

swagger注解的使用方法

@Api

@Api 注解用于标注一个Controller(Class)。
tags=”说明该类的作用,可以在前台界面上看到的注解”
value=”该参数无意义,在UI界面上看不到,不需要配置”

1
2
3
4
@Api(value = "ResFoodController", tags = "菜品的控制层")
public class ResFoodController {
. . .
}
ApiOperation

注解在用于对一个操作或HTTP方法进行描述

1
2
3
4
5
6
7
8
9
//@ApiOperation 注解在用于对一个操作或HTTP方法进行描述
@ApiOperation("根据菜品id查菜品信息")
@RequestMapping("/findById")
public Resfood findById(
@RequestParam Integer fid){
Resfood resfood = resFoodBiz.findById(fid);
return resfood;
}

@ApiParam

用在参数列表的请求参数前面,对参数进行描述或说明是否为必添项等说明

1
2
3
public Resfood findById(
@ApiParam(name = "fid",value = "菜品的id号")
@RequestParam Integer fid)
@ApiImplicitParam

@ApiImplicitParams:⽤在⽅法上包含⼀组参数说明

@ApiImplicitParam:⽤在@ApiImplicitParams注解中,指定一个请求参数的各个方面

  • name: 参数名

  • value: 参数的说明、解释

  • required: 是否必须传参

  • paramType:参数放什么位置

    path: 以地址的形式提交数据

    query: 直接跟参数完成⾃动映射赋值

    body: 以流的形式提交 仅⽀持POST

    header: 参数在request headers⾥边提交

    form: 以form表单的形式提交仅⽀持POST

  • dataType: 参数类型,默认String,其它值dataType=”Integer”

  • defaultValue: 参数的默认值

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    @ApiImplicitParams(
    @ApiImplicitParam(
    name = "fid",
    value = "菜品的id号2",
    paramType = "query",
    dataType = "Integer"
    )
    )
    public Resfood findById( ... ){
    . . .
    }

注: @ApiImplicitParams 与 @ApiParam 同时使用时 前者的优先级会高于后者并将其覆盖掉

swagger-ui上的效果

点击Try it out,并输入你要查询的菜品id,最后点击Execte按钮就可以看到结果了

ApiModel

@ApiModel: 用在响应类上,表示一个返回响应数据的信息

**@ApiModelProerty:用在属性上,面熟响应类的属性*

  • 一般用在post 创建,使用@RequestBody的时候
  • 请求参数无法使用@ApiImplicitParam

@ApiModel注解是用在接口相关的实体类上的注解,它主要是用来对使用该注解的接口相关的实体类添加额外的描述信息,常常和@ApiModelProperty注解配合使用

@ApiModelProperty注解则是作用在接口相关实体类的属性(字段)上的注解,用来对具体的接口相关实体类中的参数添加额外的描述信息,除了可以和 @ApiModel 注解关联使用,也会单独拿出来用。

作用域不同,@ApiModel作用在类上,@ApiModel作用来属性上

ApiModelProperty属性:value、name、required 、hidden、allowEmptyValue、hidden、dataType、example

allowEmptyValue: 用来描述实体参数的值是否可以为空值。在 ApiModelProperty 注解中直接声明 allowEmptyValue属性的值即可,如果不声明该属性,则默认为false,即字段参数的值不可以为空。

hidden: 用来描述实体中参数字段是否显示在Swagger界面中,默认也是false,true表示隐藏。

example:

@ApiModelProperty注解中,example属性用于提供属性的示例值,以帮助用户理解和使用该属性。

例如,考虑以下模型类:

1
2
3
4
5
6
7
8
9
public class User {
@ApiModelProperty(example = "John Doe")
private String name;

@ApiModelProperty(example = "john.doe@example.com")
private String email;

// getter and setter methods
}

在上面的代码中,@ApiModelProperty注解用于nameemail属性,分别使用example属性指定了示例值。这些示例值可以是任何合法的属性值,用于说明属性的预期内容。

当使用此模型类生成API文档或进行验证时,示例值将被显示或用于验证输入。例如,如果使用Swagger生成API文档,示例值将在属性描述中显示出来,以帮助用户了解属性的期望格式和值。

总之,@ApiModelProperty中的example属性用于提供属性的示例值,以便在生成文档或进行验证时使用。

在swagger-ui中的呈现效果:

示例代码:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
@Data
@NoArgsConstructor
@AllArgsConstructor
@ApiModel(value = "Resfood",description = "菜品实体类")
public class Resfood implements Serializable {
@TableId(type = IdType.AUTO)

@ApiModelProperty(name="fid",value = "菜品id")
private Integer fid;
@ApiModelProperty(name = "fname",value = "菜品名称")
private String fname;
@ApiModelProperty(name = "normprice",value = "原件")
private Double normprice;
@ApiModelProperty(name = "realprice",value = "真实价")
private Double realprice;
@ApiModelProperty(name = "detail",value = "细节描述")
private String detail;
@ApiModelProperty(name = "fphoto",value = "图片")
private String fphoto;
}

postman测试

软件简介

Postman是一个接口测试工具,在做接口测试的时候,Postman相当于一个客户端,它可以模拟用户发起的各类HTTP请求,将请求数据发送至服务端,获取对应的响应结果, 从而验证响应中的结果数据是否和预期值相匹配;并确保开发人员能够及时处理接口中的bug,进而保证产品上线之后的稳定性和安全性。 它主要是用来模拟各种HTTP请求的(如:get/post/delete/put..等等),Postman与浏览器的区别在于有的浏览器不能输出Json格式,而Postman更直观接口返回的结果。

官方下载地址:

postman

postman快速开始

Mock测试 -> 模拟Web 容器环境

什么是Mock ?

在面向对象的程序设计中,模拟对象(英语:mock object)是以可控的方式模拟真实对象行为的假对象。在编程过程中,通常通过模拟一些输入数据,来验证程序是否达到预期结果。

为什么使用Mock对象 ?

使用模拟对象,可以模拟复杂的、真实的对象行为。如果在单元测试中无法使用真实对象,可采用模拟对象进行替代。

什么是MockMVC ?

MockMvc 是 SpringFramework 中的一个测试工具,用于模拟 HTTP 请求和响应的行为。MockMvc 可以模拟发送 GET、POST、PUT、DELETE 等 HTTP 请求,并验证响应的状态码、内容类型和响应体等。

Mock 快速开始

引入依赖

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
<!--    表示你的项目继承自这个 starter-parent: 项目依赖信息
依赖仲裁
-->
<parent>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-parent</artifactId>
<version>2.7.16</version>
</parent>

<dependencies>
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-test</artifactId>
</dependency>
</dependencies>

启用MockMvc

1
2
3
4
5
6
7
8
//在测试类中添加 @SpringBootTest 和 @AutoConfigureMockMvc 注释启用 MockMvc。
@RunWith(SpringRunner.class)
@SpringBootTest(classes = ResApp.class)
@AutoConfigureMockMvc
@Slf4j
public class ResAppTest {
. . .
}

注入MockMvc对象

1
2
@Autowired
private MockMvc mockMvc;

模拟Http请求

1
2
3
4
5
6
7
8
9
10
//使用 MockMvc 对象的 perform 方法模拟 HTTP 请求。
//请求路径为 “/food/findByFid”
mockMvc.perform(MockMvcRequestBuilders.get("/resfood/findById")
//设置请求的参数
.param("fid","1")
/**
*将请求的 Content-Type 设置为 application/json,
*表示请求正文的内容为 JSON 格式。*/
.contentType(MediaType.APPLICATION_JSON)
)

验证响应状态码、内容、响应体

1
2
3
4
5
6
7
8
9
10
//期望返回的 HTTP 状态码为 200。
.andExpect(MockMvcResultMatchers.status().isOk())
//期望返回的结果中,属性 data.fname 的值与预期的 resfood.getFname() 相等,忽略大小写。
.andExpect(MockMvcResultMatchers.jsonPath("$.data.fname", Matchers.equalToIgnoringCase(resfood.getFname())))
//使用 andExpect 方法验证响应的内容类型
.andExpect(content().contentType(MediaType.APPLICATION_JSON))
//在控制台打印请求和响应的详细信息。
.andDo(print())
//返回执行结果。
.andReturn();