一、接口测试基础
1、什么是接口?
接口:接口统称为API ,程序与程序之间的对接、交接;接口测试主要用于检测外部系统与系统之间以及内部各子系统之间的交互点;主要是为了检验不同组件(模块)之间数据的传递是否正确,同时接口测试还要测试当前系统与第三方系统的对接,比如:支付宝、微信、银联、财付通。
2、接口的类型
按照范围划分:系统之间的接口和程序内部的接口
系统之间的接口:多个内部系统之间的交互,内部系统与外部系统之间的交互程序
内部的接口:方法与方法之间,模块与模块之间的交互
3、什么是接口测试?
是对系统或组件之间的接口进行测试,主要是校验数据的交换、传递和控制管理过程,以及相互逻辑依赖关系。
模拟客户端向服务器发送请求,服务器接收请求后进行相应的业务处理,并向客户端返回响应数据,检查响应数据是否符合预期。
4、为什么要做接口测试?
测试可以提前介入,提早发现Bug,符合质量控制前移的理念
可以发现一些页面操作发现不了的问题
接口测试低成本高效益(底层的一个Bug能够引发上层8个左右Bug,接口测试可以实现自动化)
不同于传统的单元测试,接口测试是从用户的角度对系统进行全面的检测
5、接口测试怎么做?
使用接口测试工具来实现(比如:JMeter、Postman)
通过编写代码来实现(比如:Python + Requests)
6、接口测试流程
需求分析 —— 主要依据需求文档
API文档解析 —— 由开发人员编写接口文档(API文档)
设计接口用例设计
执行接口测试用例 —— 使用接口测试工具实现
—— 通过编写代码实现
缺陷的跟踪管理
生成测试报告
接口自动化持续集成
7、接口自动化测试
自动化测试:是把以人为驱动的测试行为转化为机器执行的一种过程。
接口自动化测试:是让程序或工具代替人工自动的完成对接口进行测试的一种过程。
二、Fiddler抓包工具
抓包:(package capture)就是将网络传输发送与接收的数据包进行截获、重发、编辑、转存等操作,也用来检查网络安全。抓包经常被用来进行数据截取等。
功能测试用到抓包工具的场景:
+ 通过抓包工具截取观察网站的请求信息,帮助我们更深入的了解网站
+ 通过抓包工具截取、观察网站的请求与返回信息,帮助测试进行BUG定位与描述
+ 通过抓包工具拦截修改请求信息,绕过界面的限制,测试服务端的功能
常用的抓包工具:**Fiddler**、Charles、F12开发人员工具等
1、Fiddler原理
+ 请求先发送给Fiddler,Fiddler接收请求后转发给服务器
+ 服务器处理请求后将响应数据返回给Fiddler,Fiddler在转发给客户端(浏览器)
2、Fiddler使用
Fiddler删除请求
- 菜单删除:
- 命令行删除:cls、clear
- 键盘delete
- 快捷键:Ctrl + X
3、Fiddler设置过滤
1. 点击Filters页签,勾选“Use Filters”
2. Hosts下方的第二个下拉框,选择“Show Only the following Hosts”
3. 在下方输入框中输入要抓包的主机地址(多个地址用英文分号隔开,如:localhost;127.0.0.1)
4. 点击右上角的“Actions”,选择“Run Filterset Now”
5. 如果取消过滤,去掉“Use Filters”的勾选
4、Fiddler断点,修改请求(请求前全局断点)
1. 进入添加会员的页面,填写正确的手机号码和其他信息
2. 打开fiddler拦截开关:Rules ==》 Automatic Breakpoints ==》 Before Requests
3. 回到添加会员界面,点击提交按钮
4. 回到Fiddler,修改【请求体】,如修改手机号码内容
5. 点击Fiddler中请求下方的绿色按钮“Run to Completion”
6. 关闭Fiddler拦截开关:Rules ==》 Automatic Breakpoints ==》 Disabled
5、Fiddler修改响应(请求后全局断点)
1. 进入添加会员的页面,填写正确的手机号码和其他信息
2. 打开fiddler拦截开关:Rules ==》 Automatic Breakpoints ==》 After Responses
3. 回到添加会员界面,点击提交按钮
4. 回到Fiddler,修改【响应体】,如修改【操作提示】的内容
5. 点击Fiddler中请求下方的绿色按钮“Run to Completion”
6. 关闭Fiddler拦截开关:Rules ==》 Automatic Breakpoints ==》 Disabled
全局断点快捷键
单个断点——请求前
在命令行输入 bpu+链接 就可以实现单个指定URL设置断点了(如果bpu打断点,再次bpu回车即可清除断点设置)
单个断点——响应后
在命令行中,输入bpafter 域名
这种方式只会对配置的域名添加断点,访问其他的可以正常访问,不会有断点
6、AutoResponder(扩展 自动响应)
1.进入AutoResponder ==》自动响应
2.选择列表左侧请求,点击【Add Rule】添加mock请求(或点击【Add Rule】手动填写请求地址)
3.选择响应结果,模拟测试场景(此处支持打开本地文件,根据文件内响应数据(例如json文件)进行mock)
4.点击右下角【save】,保存响应设置
5.勾选上方选项:
(1)Enable rules:开启或禁用自动重定向功能,勾选上时,激活规则
(2)Unmatched requests passthrough:未匹配的请求穿透,即勾选上时,不影响那些没满足我们处理条件的请求
(3)勾选了这个选项,在规则里面就可以设置是立即返回响应,还是隔多少毫秒返回响应
7、Composer(扩展 接口测试)
8、弱网测试(扩展)
概念:在当今移动互联网盛行的时代,网络的形态除了有线连接,还有2G/3G/Edge/4G/5G/Wifi等多种手机网络连接方式。不同的协议、不同的制式、不同的速率,使移动应用运行的场景更加丰富。
从测试角度来说,需要额外关注的场景就远不止断网、网络故障等情况了。对于弱网的数据定义,不同的应用所界定的含义是不一样且不清晰的,不仅要考虑各类型网络最低速率,还要结合业务场景和应用类型去划分。按照移动的特性来说,一般应用低于2G速率的都属于弱网,也可以将3G划分为弱网。除此之外,弱信号的Wifi通常也会被纳入到弱网测试场景中。
为何要进行弱网测试?
例如:进地铁、上公交、进电梯等,如果app没有对各种网络异常进行兼容处理,那么用户可能在日常生活中遇到APP闪退、ANR、数据丢失等问题。因此,app网络测试,特别是弱网测试显得尤为重要。 我当前所在项目的产品是一款适配于低资源环境的医疗IT系统,目前主要是在坦桑尼亚地区使用。根据资料显示,在坦桑尼亚等东非国家,普遍使用的都是2G网络,覆盖率达到40%以上,3G网络的覆盖都非常少,并且稳定性较差。由此,对于当前的App应用交付要求即至少在弱网以及无网状态下能正常运行。
手机弱网测试步骤
+ 打开Fiddler,设置代理,并允许远程连接
+ 手机连接电脑的热点网络,或者同在一个局域网内
+ 手机网络连接中,设置网络代理,IP是电脑的同网段IP地址,端口是8888
+ 打开网速模拟模式开关(Rules → Performances → Simulate Modem Speeds )
<img src="image/image-20200625150233765.png" alt="image-20200625150233765" style="zoom:67%;" />
+ 手机访问APP,或者用手机浏览器访问网络,观察功能响应或者页面刷新速度
+ 如果需要自定义网络的速度,需要到自定义规则中配置(Rules → Customize Rules)
网络环境测试机带宽参考测试数据
9、HTTPS请求(扩展)
三、 HTML与HTTP协议
+ URL:统一资源定位符
+ HTML:超文本标记语言
+ HTTP:超文本传输协议
URL
示例:`http://localhost/index.php?m=Home&c=Goods&a=goodsInfo&id=46`
格式:
协议:客户端和服务器通讯的标准,http、https、ssh等
ip或域名
端口号:协议默认的端口号是可以省略的
http:默认端口80
https:默认端口443
ssh:默认端口22
资源路径:资源存放的位置,资源可以是各种超文本信息,如音频、视频等 参数(如`?m=Home&c=Goods&a=goodsInfo&id=46`)
格式:
用?与URL的主体部分分开 参数的格式`参数名=参数值`,有多个参数时用&拼接即可
URL:(Uniform Resource Locator)统一资源定位符,是互联网上标准资源的地址。HTTP使用URL来建立连接和传输数据。
URL格式:
http://www.tpshop.com/index.php?m=Admin&c=Admin&a=login
解析: 协议部分:“http”,常见的协议有HTTP,HTTPS、FTP等
域名部分:“www.tpshop.com”,也可以使用IP地址作为域名使用
端口部分:“8080”,端口可以省略,默认端口(HTTP:80,HTTPS:443,FTP:21)
资源路径部分:“/index.php”
查询参数部分:“m=Admin&c=Admin&a=login”,可以允许有多个参数,多个之间用“&”作为分隔符
1、HTML
HTML:HyperText Markup Language ,超文本标记语言
超文本:声音、视频、图片、超链接等
标记:就是通过【<标记符>内容</标记符>】的格式让内容具有不同的表现形式,从而达到超文本的目的 如:` <title>百度一下,你就知道</title> `
互联网上浏览的网页,本质上就是超文本标记语言。
2、HTTP
HTTP: HyperText Transfer Protocol ,超文本传输协议,是互联网上最常用的协议之一。
3、协议介绍
HTTP:(HyperText Transfer Protocol)超文本传输协议,是一个基于请求与响应模式的、应用层的协议,服务器传输超文本到本地浏览器的传送协议,也是互联网上应用最为广泛的一种网络协议,端口号是80。
HTTP协议的工作原理:HTTP协议工作于客户端-服务端架构为上。浏览器作HTTP客户端通过URL向 HTTP服务端即WEB服务器发送所有请求。Web服务器根据接收至啲请求后,向客户端发送响应信息。
HTTPS (全称:Hypertext Transfer Protocol Secure,超文本传输安全协议),WEB服务存在http和https两种通信方式,http对于传输采用不加密的方式,https 默认采用443端口,在HTTPS数据传输的过程中,需要用SSL/TLS对数据进行加密 和解密。
TCP传输控制协议(Transmission Control Protocol),是一种面向连接的、可靠的、基于字节流的传输层通信协议,电脑是通过增删改查这交互的。其中中间有一个TCP传输层,让电脑和服务器建立连接的,它是采用三次握 手确认建立一个连接。四次挥手,终止TCP连接。
其他的协议和端口
telnet 远程登入协议 23
FTP 文件传输协议 21
SMTP 由K件传输协议 25
DNS 域名解析协议 53
POP3 邮件服务器 110
UDP 用户数据报协议
OSI 网络协议
IOS 苹果操作系统
ISO 镜像文件格式
4、HTTP协议的特点
支持客户端/服务器模式
简单快速
灵活
无连接
无状态
HTTP和HTTPS区别
1、http是超文本传输协议,他也是互联网上使用最多的一种网络协议,http是以明文的方式传输信息的,所以http在 网络上并不安全。
2、https是http的安全版,https在http的基础上嵌套了一层ssl的安全协议,简单来说就是https要比http更加安全。
3、http的端口是80,https的端口是443,http的传输速度比https要快。
4、https主要是用来确认网站的真实性和保证数据传输的安全。
5、HTTP请求
http请求由三部分组成,分别是:请求行、请求头、请求体
请求行
请求行:请求行用来说明请求方法、要访问的资源以及所使用的协议版本
常用请求方法:
GET:从服务器获取资源(一项或多项),请求指定的页面信息,并返回实体主体,请求参数一般放在url地址栏的后面。 ==》 查询数据
POST:在服务器新建一个资源,向指定资源提交数据进行处理请求(例如提交表单或者上传文件)。数 据被包含在请求体中。 ==》新增数据
PUT:在服务器更新资源(客户端提供改变后的完整资源),从客户端向服务器传送的数据取代指定的文档的内容。
==》修改数据
DELETE:从服务器删除资源,请求服务器删除指定的页面。 ==》删除数据
其他请求方法(了解):
HEAD:请求获取由Request-URI所标识的资源的响应消息报头,类似于get请求,只不过返回的响应中没有具体的内容,用于获取报头。
TRACE:请求服务器回送收到的请求信息,主要用于测试或诊断。
CONNECT:保留将来使用,HTTP/1.1协议中预留给能够将连接改为管道方式的代理服务器。
OPTIONS:请求查询服务器的性能,或者查询与资源相关的选项和需求。
GET和POST的区别
- 最直观的区别就是GET把参数包含在URL中,POST通过request body(请求体)传递参数。
- GET比POST更不安全,因为参数直接暴露在URL上,所以不能用来传递敏感信息。
- GET在浏览器回退时是无害的,而POST会再次提交请求。
- GET请求只能进行url编码,而POST支持多种编码方式。
- GET请求参数会被完整保留在浏览器历史记录里,而POST中的参数不会被保留。
- GET请求在URL中传送的参数是有长度限制的(2048字节),而POST没有(注意:这个限制是由浏览器导致)。
- 对参数的数据类型,GET只接受ASCII字符,而POST没有限制。
请求方法之get请求
1) 请求的数据一般会显示在地址栏
2) 安全性差,请求的入参信息全部暴露在URL地址栏当中
3) 请求的数据量比较小
请求方法之post请求
1) 请求的数据一般不会显示在地址栏里面,会把数据封装在表单里面(入参放在 requests body当中)再提交
2) 安全性比较高
3) 请求的数据量比较大
请求头
请求头:紧接着请求行,请求头部由键值对组成,每行一对。 请求头部通知服务器有关于客户端请求的信息。
post :表示请求的方法。
HTTP/1.1 :表示超文本传输协议版本为1.1版本UR礙一资源定位符。
Host:域名Host表示请求的服务器网址。
Connection::表示客户端与服务连接类型。
Content-Length:用来说明传输的正文大小或者内容长度。
Keep-Alive:表示持久连接
Accept:客户端可识别的内容类型列表,浏览器支持的MIME消息内容类型。
常见的类型:
text html、application/xhtml+xmls、application/xml和*/*
优先顺序是它们从左到右的排列顺序
X-Requested-With:标识Ajax请求,大部分js框架发送请求时都会设置它为XMLHttpRequest
User-Agent:产生请求的浏览器类型,用户代理的字符串值浏览器的身份标识字符串。 Content-Type:请求体数据的类型,设置请求体的MlME类型。
常见的类型有:
text/html: HTML格式
text/plain:纯文本格式
image/jpeg:jpg图片格式
application/json: JSON数据格式
application/x-www-form-urlencoded: form表单数据被编码为key/value格式发送到服务器(表单默认的提交数据格式)
multipart/form-data: 在表单中进行文件上传时使用
origin:标识跨域资源请求。
Referer :设置前一个页面的地址,并且前一个页面中的连接指向当前请求。
Accept-Encoding :设置接受的编码格式 Accept-Encoding: gzipf deflate 。
Accept-Language :设置接受的语言。
Accept-Language::en-US 是英文 zh-cn为中文 。
Cookie:设置服务器使用Set-Cookie发送的http cookie Cookie的作用就是用于解决 记录客户端的用户信息当用户下一次访问该web页面时,可以在cookie中读取用户访问记录。
请求体
请求体:
请求体不在GET方法中使用,经常在POST、PUT方法中使用
请求体的数据可以是:表单数据、文本、XML、JSON
与请求数据相关的最常使用的请求头是Content-Type和Content-Length
6、HTTP响应
HTTP响应也由三个部分组成,分别是:状态行、响应头、响应体
HTTP/1.1:表示超文本传输协议版本为1.1版本URL统一资源定位符
Server:服务器名称 Server: Apache/2.4.1 (Unix)
Set-Cookie:设置HTTP Cookie Set-Cookie: UserlD=JohnDoe; Max-Age=3600;Version=1
Content-Type:设置响应体的MIME类型 Content-Type: text/html; charset=utf-8
Transfer-Encoding:设置传输实体的编码格式,目前支持的格式:chunked, compress, deflate, gzip, identity
Date:设置消息发送的日期和时间Date: Tue, 15 Nov 1994 08:12:31 GMT 4)
状态行
状态行
状态行由协议版本号、状态码、状态消息三部分组成
状态码有三位数字组成,第一个数字定义了响应的类别:
1xx:指示信息--表示请求已接收,继续处理
2xx:成功--表示请求已被成功接收、理解、接受
3xx:重定向--要完成请求必须进行更进一步的操作
4xx:客户端错误--请求有语法错误或请求无法实现
5xx:服务器端错误--服务器未能实现合法的请求
响应头
响应头用于描述服务器的基本信息,以及数据的描述,服务器通过这些数据的描述信息,可以通知客户端如何处理响应数据
响应体
响应体就是响应的消息体,数据可以是普通文本、XML、JSON、HTML源码
状态码 | 状态消息 | 动词 | 说明 |
200 | OK | [GET] | 服务器成功返回用户请求的数据 |
201 | CREATED | [POST/PUT] | 用户新建或修改数据成功 |
202 | Accepted | [*] | 表示一个请求已经进入后台排队(异步任务) |
204 | NO CONTENT | [DELETE] | 用户删除数据成功 |
400 | Bad Request | [POST/PUT] | 客户端请求有语法错误,不能被服务器所理解 |
401 | Unauthorized | [*] | 表示用户没有权限(令牌、用户名、密码错误) |
403 | Forbidden | [*] | 表示用户得到授权(与401错误相对),但是访问是被禁止的 |
404 | Not Found | [*] | 请求资源不存在,eg:输入了错误的URL |
406 | Not Acceptable | [GET] | 用户请求的格式不可得(比如用户请求JSON格式, 但是只有XML格式) |
410 | Gone | [GET] | 用户请求的资源被永久删除,且不会再得到的 |
500 | INTERNAL SERVER ERROR | [*] | 服务器发生错误,用户将无法判断发出的请求是否成功 |
503 | Server Unavailable | [*] | 服务器当前不能处理客户端的请求,一段时间后可能恢复正常 |
7、接口文档
接口文档:又称为API文档,一般是由开发人员所编写的,用来描述系统所提供接口信息的文档。
为什么要写接口文档?
1、能够让前端开发与后台开发人员更好的配合,提高工作效率。(有一个统一参考的文件)
2、项目迭代或者项目人员更迭时,方便后期人员查看和维护。
3、方便测试人员进行接口测试。
接口文档内容:
基本信息:接口名称、请求方法、请求路径(path)、接口描述
请求参数:请求头(hearders)、请求体body(包含具体的请求参数名称、参数类型、是否必须、示例、备注)
返回数据:不同情况的响应状态码、响应数据(包含具体的响应数据名称、类型、是否必须、默认值、示例、备注)
8、接口测试的测试点
接口用例设计的方法与思
功能测试:验证接口功能是否按照接口文档实现(输入+处理+输出)
单接口测试
正向功能:(通过性测试)
仅必填参数
全部参数参数组合
反向测试:(异常测试)
参数异常:无参、少参、多参、错误参数
数据异常:数据为空、长度不符、类型不符、错误数据
业务数据异常:结合业务功能考虑输出的各种异常返回情况
多接口测试:业务场景功能测试(站在用户角度考虑常用的使用场景)
接口之间数据依赖
性能测试
安全测试
敏感数据是否加密
敏感数据是否遮挡
敏感数据是否可以被复制
敏感数据是需要加密的
敏感数据加密需要一定的难度(不容易被暴力破解)
SQL注入
其他
单接口测试用例
正常测试
全部必填参数
全部参数(必填+非必填)
参数组合(必填+部分非必填)
异常测试
数据异常:长度、类型、是否为空、不满足业务等(注意:与功能测试一模一样) 参数异常:多参、少参、无参、错误参数等(注意:这个是接口测试新出现的测试点)
业务异常:关注业务上的异常(测试关注点:各种异常状态码测试)
业务场景测试(多接口测试)
将多个业务场景涉及的接口进行组合测试
注意:接口调用的先后顺序即可
接口测试用例模板
ID、模块、用例标题、接口名称、请求URL、请求方法、请求头、请求数据类型、请求体(请求参数))、 预期结果(响应):响应状态码、响应数据
四、Postman实现接口测试
1、Postman基本用法
设置请求方式
输入请求路径
设置请求数据
点击发送请求
查看响应数据
需求:--提交字符串数据 get
1、访问TPshop搜索商品的接口,通过查询字符串的方式传递搜索的关键字 iPhone ,并查看响应数据
2、请求路径格式为:http://www.tpshop.com/Home/Goods/search.html?q=iPhone
需求:--提交form表单数据 post
1、请求TPshop项目的登录接口,请求数据(username: 15788888888, password: 123456, verify_code: 8888)
2、登录接口URL:http://www.tpshop.com/index.php?m=Home&c=User&a=do_login
实现分析:
请求方式:POST
请求路径: http://www.tpshop.com/index.php?m=Home&c=User&a=do_login
请求数据:请求体-表单提交(username: 15788888888, password: 123456, verify_code: 8888)
需求:
1.请求IHRM项目的登录接口,请求数据({"mobile":"13800000002","password":"123456"})
2.登录接口地址URL:http://ihrm-test.itheima.net/api/sys/login
实现分析:
请求方式:POST
请求路径: http://ihrm-test.itheima.net/api/sys/login
请求数据:JSON数据{"mobile":"13800000002","password":"123456"}
2、Postman高级用法
实现步骤
1、创建测试集-New Collection
Collection可以理解成一个项目(系统),包含多个接口请求
创建测试集- 点击‘New Collection’,在弹出框中输入测试集的名称和其他信息,再点击‘Create’按钮
2、创建目录-Add Folder
Folder可以理解成一个项目模块 创建目录- 在测试集上点击右键选择‘Add Folder’,在弹出框中输入目录的名称和其他信息,再点击‘Create’按钮
3、添加请求-Add Request
添加请求- 在目录上点击右键选择‘Add Request’,在弹出框中输入请求的名称和其他信息,再点击保存按钮
3、Postman断言
断言:让程序判断预期结果和实际结果是否一致。
Postman的断言是使用JavaScript语言编写的,写在‘Tests’标签页里
Tests中的脚本在发送请求之后执行,会把断言的结果(PASS/FAIL)最终在‘Test Results’标签页中展示
常用Postman断言: 在Tests输入框的右侧配置了一些常用的断言代码片段,点击后自动填写到Tests输入框中,然后再进行修改
断言介绍: Status code: Code is 200
// 判断响应状态码是否等于200
pm.test("Status code is 200", function (){
pm.response.to.have.status(200);
});
断言介绍: Response body: Contains string
// 判断响应体中是否包含指定的字符串
pm.test("Body matches string", function () { pm.expect(pm.response.text()).to.include("string_you_want_to_search");
});
断言介绍: Response body: Is equal to a string
// 判断响应体数据是否等于指定的字符串
pm.test("Body is correct", function () {
pm.response.to.have.body("response_body_string");
});
断言介绍: Response body: JSON value check
// 校验响应的JSON数据
pm.test("Your test name", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.value).to.eql(100);
});
断言介绍: Response headers: Content-Type header check
// 判断响应头中是否包含指定的头标签
pm.test("Content-Type is present", function () {
pm.response.to.have.header("Content-Type");
});
4、postman 设置变量
全局变量与环境变量
全局变量:全局变量是全局唯一的,不可重复定义的变量
环境变量:
一个变量只能属于某个环境,在某一个环境中变量不可重复定义
在环境与环境之间可以定义重复的变量
一个环境可以包含多个环境变量
常见环境分类:开发环境、测试环境、生产环境
// 设置环境变量
pm.environment.set("e_name", "rose");
// 设置全局变量 pm.globals.set("g_name", "jack");
pm.environment.get("variable_key");
pm.globals.get("variable_key");
// 获取环境变量的值 mobile2和password2
var mobile = pm.environment.get("mobile2");
var password = pm.environment.get("password2");
console.log("测试环境中的mobile是:" + mobile)
console.log("测试环境中的password是:" + password)
5、前置处理
请求前置脚本
请求前置脚本就是在“Pre-request Script”标签中所编写的脚本,是在请求发送之前要执行的代码片段。
应用场景:
请求参数中包含一个随机数或者时间戳
请求之前需要对请求参数做进一步处理(如:对敏感参数进行加密)
需求:请求TPshop项目中获取图片验证码的接口,需要在URL中设置随机数
请求路径: http://www.tpshop.com/index.php?m=Home&c=User&a=do_login&t=0.048764603803752804
分析:在JS中如何生成随机数? var t = Math.random(); // 返回[0, 1)之间的随机数
// 生成随机数
var r = Math.random() console.log("生成的随机数:", r)
// 通过全局变量保存随机数
pm.globals.set("g_random", r);
6、关联接口
关联接口:后一个接口的请求需要依赖前一个接口的响应数据,一般通过全局变量或者环境 变量来进行参数在接口之间的传递。
当请求之间有依赖关系,比如一个请求的入参是另一个请求返回的数据,这时候就需要用到关联处理。)
要获取某个请求的响应结果数据,可以通过在‘Tests’标签页中编写JavaScript脚本来实现
// 获取JSON格式的响应数据
var jsonData = pm.response.json();
多个请求之间可以使用全局变量或环境变量来传递数据
// 把数据保存到全局变量中
pm.globals.set("city", city);
获取某个全局变量的值:{{var_name}}
案例1:
1.请求获取天气接口,http://www.weather.com.cn/data/sk/101010100.html
2.获取天气接口返回结果中的城市名称
3.请求百度搜索接口:http://www.baidu.com/s?wd={{城市名称}},城市名称即为天气接口获取并保存 到全局变量中的数据。
7、批量执行测试用例
要想批量执行测试用例,需要先把接口请求添加到测试集中,通过运行测试集的方式就可以实现批量运行测试用例。
操作步骤
1、点击测试集中的“Run”按钮,批量运行测试用例
2、弹出Collection Runner窗口,点击运行按钮
3、查看测试结果
8、参数化
读取外部文件实现参数化
应用场景: 针对于某个接口,如果有大量的测试数据需要批量验证,可以把测试数据保存到数据文件中,通过参数化的方式来实现。
常用的数据文件格式有:CSV、JSON
需求:批量查询手机号归属地和所属运营商信息,并校验运营商数据是否正确
接口地址: http://cx.shouji.360.cn/phonearea.php?number=13012345678
部分测试数据:
手机号 : 13012345678 运营商: 联通手机号: 13800001111 运营商: 移动手机号: 18966778899 运营商: 电信
9、Postman测试报告
Newman是一款基于nodejs开发的可以运行Postman脚本的工具,并可以生成测试报告
安装nodejs
打开cmd输入: npm install -g newman
校验:安装完成后,输入 newman -v 命令查看版本信息,检测是否安装成功
安装newman-reporter-html
打开cmd输入: npm install -g newman-reporter-html
安装nodejs
下载地址: h ttp://nodejs.cn/download/ windows系统直接双击运行安装包,如【node-v12.10.0-x64.msi】
校验:打开cmd输入【node -v】,看到输出node版本信息,即代表成功
安装newman
打开cmd,输入【npm install -g newman】
校验:输入【newman -v】
安装newman-reporter-html
打开cmd输入:【npm install -g newman-reporter-html】
输出测试报告步骤: 1、导出测试集数据
2、使用newman命令,运行导出的测试集脚本,打开cmd输入:
newman run 测试脚本文件 -e 环境变量文件 -d 测试数据文件 -r html --reporter-html-export report.html
例如:
newman run demo.postman_collection.json -r html
newman run demo.postman_collection.json -r html --reporter-html-export report.html
命令说明:
run xxx.json:表示要执行的postman脚本,即导出的测试集数据
-e source:用来指定环境变量文件的路径
-d source:用来指定测试数据文件的路径
-r html:用来指定生成的数据结果的类型,如json、html等
-reporter-html-export source:指定html报告生成的路径;如果不设置该参数,则会在当前目录下生成一个名字为newman的文件夹
五、PyMysql操作数据库
1、安装:pip install PyMySQL
验证: pip show PyMySQL
2、操作流程
创建连接
获取游标
执行sql
查询操作(select)
非查询操作(insert/update/delete)
事务提交(连接对象.commit())
事务回滚(连接对象.rollback())
关闭游标
关闭连接
什么是游标?
游标是SQL 的一种数据访问机制 ,游标是一种处理数据的方法。 众所周知,使用SQL的select查询操作返回的结果是一个包含一行或者是多行的数据集,如果 我们要对查询的结果再进行查询,比如(查看结果的第一行、下一行、最后一行、前十行等 等操作)简单的通过select语句是无法完成的,因为这时候索要查询的结果不是数据表,而是 已经查询出来的结果集。 游标就是针对这种情况而出现的。
可以将“ 游标 ”简单的看成是结果集的一个指针,可以根据需要在结果集上面来回滚动, 浏览我需要的数据。
数据准备:
CREATE DATABASE if not EXISTS books DEFAULT charset utf8;
use books;
Drop TABLE if EXISTS `t_book`;
CREATE TABLE `t_book`( `id` int(11) not null auto_increment, `title` VARCHAR(20) not NULL COMMENT '图书名称', `pub_date` date not NULL COMMENT '发布日期', `read` int(11) not null default '0' comment '阅读量', `comment` int(11) not null default '0' comment '评论量', `is_delete` TINYINT(1) not NULL DEFAULT '0' COMMENT '逻辑删除', PRIMARY KEY(`id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='图书表';
INSERT into `t_book` VALUES ('1','射雕英雄传','1980-05-01','12','34','0');
INSERT into `t_book` VALUES ('2','天龙八部','1986-07-24','36','40','0');
INSERT into `t_book` VALUES ('3','笑傲江湖','1995-12-24','20','80','0');
数据准备:
Drop TABLE if EXISTS `t_hero`;
CREATE TABLE `t_hero`( `id` int(11) not null auto_increment, `name` VARCHAR(20) not NULL COMMENT '姓名', `gender` SMALLINT(6) not NULL COMMENT '性别', `description` VARCHAR(200) default NULL comment '描述', `is_delete` TINYINT(1) not NULL DEFAULT '0' COMMENT '逻辑删除', `book_id` int(11) not null comment '所属图书ID', PRIMARY KEY(`id`), key `t_hero_book_id`(`book_id`) )ENGINE=INNODB DEFAULT CHARSET=utf8 COMMENT='英雄人物表';
INSERT into `t_hero` VALUES ('1','郭靖','1','降龙十八掌','0','1');
INSERT into `t_hero` VALUES ('2','黄蓉','0','打狗棍法','0','1');
INSERT into `t_hero` VALUES ('3','乔峰','1','降龙十八掌','0','2');
INSERT into `t_hero` VALUES ('4','令狐冲','1','独孤九剑','0','3');
INSERT into `t_hero` VALUES ('5','任盈盈','0','弹琴','0','3');
3、数据库查询操作
连接到数据库
host:localhost
user:root
password:root
database:books
查询图书表的数据
(包括:图书id、图书名称、阅读量、评论量)
获取查询结果的总记录数
获取查询结果的第一条数据
获取全部的查询结果
4、数据库插入操作
新增一条图书数据(id:4 title:西游记 pub_date:1986-01-01 )
5、数据库更新操作
更新[西游记]图书名称为(title:东游记)
6、数据库删除操作
删除图书(title:东游记)
7、数据库事务操作
-- 抛出异常,连接数据库查看
数据不一致性问题
1).连接到数据库(host:localhost user:root password:root database:books), 并开启自动提交事务
2).新增一条图书数据(id:4 title:西游记 pub_date:1986-01-01 )
3).故意抛出一个异常(模拟代码出现异常)
4).新增一条英雄人物数据(name:孙悟空 gender:1 book_id:4)
8、数据库工具封装
1、创建连接
2、创建游标
3、执行sql
try:
# 获取游标对象
# 调用游标对象.execute(sql)
# 如果是查询:
# 返回所有数据
# 否则:
# 提交事务
# 返回受影响的行数
except:
# 回滚事务
# 抛出异常
finally:
# 关闭游标
# 关闭连接
4、关闭游标
5、关闭连接
-- 验证
六、代码实现接口测试
1、Requests库
设置请求方式为
输入请求路径
设置请求数据
点击发送请求
查看响应数据
Requests库是用Python编写的,基于urllib,采用Apache2 Licensed开源协议的HTTP库;
相比urllib库, Requests库更加方便,可以节约我们大量的工作,完全满足HTTP测试需求;
安装:pip install requests
常见的HTTP请求方式:GET、POST、PUT、DELETE
2、GET请求
3、POST请求
4、其他请求类型
其他 HTTP 请求类型,比如:PUT、DELETE、HEAD 以及 OPTIONS。
import requests
response = requests.put("http://www.baidu.com", data={"key": "value"})
response = requests.delete("http://www.baidu.com")
response = requests.head("http://www.baidu.com")
response = requests.options("http://www.baidu.com")
5、响应内容
请求方法的返回值response为 Response 对象, 我们可以从这个对象中获取所有我们想要的响应信息。
response.status_code 状态码
response.url 请 求
url response.encoding 查看响应头部字符编码
response.headers 头信息
response.cookies cookie信息
response.text 文本形式的响应内容
response.content 字节形式的响应内容
response.json() JSON形式的响应内容
案例:
1).访问百度首页的接口`http://www.baidu.com`,获取以下响应数据
2).获取响应状态码
3).获取请求URL
4).获取响应字符编码
5).获取响应头数据
6).获取响应的cookie数据
7).获取文本形式的响应内容
8).获取字节形式的响应内容
6、JSON 响应内容
如果请求响应的内容为JSON格式的数据,则可以直接调用 response.json() 方法获取数据,因为requests中内置了JSON解码器, 帮助我们处理JSON数据
7、设置请求头
8、获取响应信息中的cookie数据
cookies = response.cookies
发送请求时添加cookie数据,可以使用 cookies 参数
requests.get(url, cookies={"c1": "v1"})
9、Session会话
session对象代表一次用户会话:从客户端 浏览器连接服务器开始,到客户端浏览器 与服务器断开会话能让我们在跨请求时候 保持某些参数,比如在同一个 session 实例发出的所有请求之间保持cookie
10、UnitTest
将接口测试脚本集成到UnitTest单元测试框架中,利用UnitTest的功能来运行接口测试用例。
目的:
1.方便管理和维护多个测试用例
2.提供丰富的断言方法
3.能够生成测试报告
需求: 使用TPShop项目完成对登录功能的接口测试
# 导包
import requests
import unittest
# 创建测试类
class TPShopLogin(unittest.TestCase):
def setUp(self):
# 实例化session对象
self.session = requests.Session()
# 定义验证码接口url地址
self.url_verify = "http://www.tpshop.com/index.php?m=Home&c=User&a=verify"
# 定义登录接口url地址
self.url_login = "http://www.tpshop.com/index.php?m=Home&c=User&a=do_login"
# teardown
def tearDown(self):
# 关闭session对象
self.session.close()
# 登录成功
def test01_success(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code) # 断言等于
self.assertIn("image", response.headers.get("Content-Type")) # 断言包含
# 发登录请求并断言
login_data = {
"username":"15708460952",
"password":"123456",
"verify_code":"8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.json().get("status"))
self.assertIn("登陆成功", response.json().get("msg"))
# 账号不存在
def test02_user_is_not_exist(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": "13488888899",
"password": "123456",
"verify_code": "8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-1, response.json().get("status"))
self.assertIn("账号不存在", response.json().get("msg"))
# 密码错误
def test03_password_error(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": "15708460952",
"password": "error",
"verify_code": "8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-2, response.json().get("status"))
self.assertIn("密码错误", response.json().get("msg"))
11、接口测试框架开发
接口测试框架的结构说明:
1、API 用于封装被测系统的接口
2、TestCase 将一个或者多个接口 封装成测试用例,并使用UnitTest 管理测试用例
3、TestCase 可以调用数据库进行 数据的校验
4、为了方便维护测试数据,可以 把测试脚本和测试数据分离开
5、通过UnitTest断言接口返回的 数据,并生成测试报告
框架目录结构
apiTestFramework # 项目名称
├── api # 定义封装被测系统的接口
├── script # 定义测试用例脚本
├── data # 存放测试数据
├── report # 存放生成的测试报告
├── lib # 存放第三方的文件
├── app.py # 定义项目的配置信息
├── utils.py # 定义工具类
└── run_suite.py # 执行测试套件的入口
封装被测系统的接口
按照功能模块定义封装被测系统的接口,方便测试脚本的调用,并且能够到达代码的复用。
对登录功能的相关接口进行封装,示例代码模块:# api/login.py
class LoginApi:
def init (self):
self.verify_code_url = "http://localhost/index.php?m=Home&c=User&a=verify"
self.login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
# 获取验证码
def get_login_verify_code(self, session):
return session.get(self.verify_code_url)
# 登录接口
def login(self, session, username, password, verify_code):
# 发送请求
data = {"username": username, "password": password, "verify_code": verify_code,}
return session.post(self.login_url, data=data)
定义接口测试用例
将api模块中的一个或多个接口封装成一个测试用例,并使用测试框架UnitTest管理测试用例。
定义登录功能的测试用例,示例代码模块:# scripts/test01_login.py
import unittest
import requests
from requests import Session
from api.login import LoginApi
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.login_api = LoginApi()
def setUp(self):
self.session = Session()
def tearDown(self):
self.session.close()
# 登录成功
def test_login_success(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13012345678", "123456", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(1, result.get("status"))
self.assertEqual("登陆成功", result.get("msg"))
# 账号不存在
def test_login_username_not_exist(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13088888888", "123456", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-1, result.get("status"))
self.assertIn("账号不存在", result.get("msg"))
# 密码错误
def test_login_password_is_error(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13012345678", "error", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-2, result.get("status"))
self.assertIn("密码错误", result.get("msg"))
集成测试报告
使用HTMLTestRunner生成HTML格式的测试报告,代码模块:run_suite.py
import time
import unittest
from script.test_login import TestLogin
from tools.HTMLTestRunner import HTMLTestRunner
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))
# 测试报告文件路径
report_file = "./report/report{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
with open(report_file, "wb") as f:
# 创建HTMLTestRunner运行器
runner = HTMLTestRunner(f, title="TPshop接口自动化测试报告",description="V1.0")
# 运行测试套件
runner.run(suite)
12、基于json文件实现参数化
[
{
"desc": "case01 登录成功",
"username": "15708460952",
"password": "123456",
"verify_code": "8888",
"content_type": "image",
"status_code": 200,
"status": 1,
"msg": "登陆成功"
},
{
"desc": "case02 账号不存在",
"username": "13488888899",
"password": "123456",
"verify_code": "8888",
"content_type": "image",
"status_code": 200,
"status": -1,
"msg": "账号不存在"
},
{
"desc": "case03 密码错误",
"username": "15708460952",
"password": "error",
"verify_code": "8888",
"content_type": "image",
"status_code": 200,
"status": -2,
"msg": "密码错误"
}
]
代码模块:test02_login_params.py
"""
定义接口测试用例
使用unittest
1.导包
2.创建测试类
2.1 前置处理
2.2 后置处理
2.3.创建测试方法
"""
# 导包
import json
import requests
import unittest
from api.login import LoginAPI
from parameterized import parameterized
# 构造测试数据
def build_data():
json_file = "../data/login.json"
test_data = []
with open(json_file, encoding="utf-8") as f:
json_data = json.load(f)
for case_data in json_data:
username = case_data.get("username")
password = case_data.get("password")
verify_code = case_data.get("verify_code")
status_code = case_data.get("status_code")
content_type = case_data.get("content_type")
status = case_data.get("status")
msg = case_data.get("msg")
test_data.append((username, password, verify_code, status_code, content_type, status, msg))
print("test_data = {}".format((username, password, verify_code, status_code, content_type, status, msg)))
return test_data
python读取json文件:
1、先将我们的json编写完成放入data层,该文件中包含入参信息,响应结果等,由api文档得来
2、在我们的test_case层进行测试用例的编写
3、在tast_case中导入request库、json库、parameterized库(参数化)
4、首先定义一个构建测试数据的方法,该方法中将json格式文件赋值给json_file变量,并定义1个空的列表,如test_data=[], 用open的方式打开我们刚才定义的json格式文件路径的变量json_file,使用json.load()读取该文件的内容并赋值给1个变量json_data,
5、使用for 循环对这个变量进行遍历并赋值,将json文件中的比如username,password,veryfy_code,msg,content_Type等进行遍历赋值。
6、遍历后的结果通过.append的方法追加到之前定义的空列表test_data[]中,并将结果返回
7、接下来就是编写用例,定义1个类,继承unittest.testcase属性 定义setup方法的开始,里面装事先写好的url,创建session会话等,每次执行用例时先执行该方法 定义teardown方法的结束,里面是关闭session会话,每次执行用例完毕后执行该方法
8、然后会用到parameterized.expand这个装饰器进行入参的传入就可以了
python读取xls文件
1、读取xls表格文件的话首先将写好的xls文件放入我们的data层
2、我们会用到读取xls文件的1个代码包在我们的utils包中,在这个文件中,我们会用到xlrd模块来读取表格数据
3、然后使用os.path.jion的方法将路径赋值给file变量
4、使用xlrd.open获取该文件内容并赋值给1个变量如book
5、用book.sheet的方式去选择sheet界面的内容并赋值给变量sheet
6、使用sheet.nrows获取文本中的有效行数
7、创建1个空列表list1
8、使用for循环对文件行数进行遍历,使用sheet.row_values获取每一行的内容
9、使用append进行追加到之前定义的空列表list1中
10、再讲列表进行return返回就可以了
parameterized.expand 参数化装饰器
# 定义测试类
class TestLoginAPI(unittest.TestCase):
# 前置处理
def setUp(self):
self.login_api = LoginAPI() self.session = requests.Session()
# 后置处理
def tearDown(self):
if self.session:
self.session.close()
# 定义测试方法
@parameterized.expand(build_data)
def test01_login(self, username, password, verify_code, status_code, content_type, status, msg):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(status_code, response.status_code)
self.assertIn(content_type, response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, username, password, verify_code)
print(response.json())
self.assertEqual(status_code, response.status_code)
self.assertEqual(status, response.json().get("status"))
self.assertIn(msg, response.json().get("msg"))
13、基于数据库实现参数化(扩展)
数据库数据准备:
DROP TABLE IF EXISTS `t_login`;
CREATE TABLE `t_login` ( `id` int(11) NOT NULL AUTO_INCREMENT, `case_desc` varchar(100) NOT NULL COMMENT '用例描述', `username` varchar(11) NOT NULL COMMENT '用户名', `password` varchar(16) NOT NULL COMMENT '密码', `verify_code` varchar(4) NOT NULL COMMENT '验证码', `status_code` int(3) NOT NULL DEFAULT '0' COMMENT '响应状态码', `content_type` varchar(11) NOT NULL COMMENT 'Content-Type', `status` int(1) NOT NULL DEFAULT '0' COMMENT '业务状态码', `msg` varchar(100) NOT NULL COMMENT '业务状态消息', PRIMARY KEY (`id`) ) ENGINE=InnoDB AUTO_INCREMENT=4 DEFAULT CHARSET=utf8 COMMENT='TPshopLogin参数化';
INSERT INTO `t_login` VALUES ('1', 'case01登录成功', '13488888888', '123456', '8888', '200', 'image', '1', '登陆成功');
INSERT INTO `t_login` VALUES ('2', 'case02账号不存在', '13488888899', '123456', '8888', '200', 'image', '-1', '账号不存在');
INSERT INTO `t_login` VALUES ('3', 'case03密码错误', '13488888888', 'error', '8888', '200', 'image', '-2', '密码错误');
代码模块:读取数据库dbutil.py
# 导包
import pymysql
# 创建工具类
class DBUtil():
# 初始化
__conn = None
__cursor = None
# 创建连接
@classmethod
def __get_conn(cls):
if cls.__conn is None:
cls.__conn = pymysql.connect(host="localhost",port=3306,user="root",password="root",database="books")
return cls.__conn
# 获取游标
@classmethod
def __get_cursor(cls):
if cls.__cursor is None:
cls.__cursor = cls.__get_conn().cursor()
return cls.__cursor
# 执行sql
@classmethod
def exe_sql(cls, sql):
try:
# 获取游标对象
cursor = cls.__get_cursor()
# 调用游标对象的execute方法,执行sql
cursor.execute(sql)
# 如果是查询
if sql.split()[0].lower() == "select":
# 返回所有数据
return cursor.fetchall()
# 否则:
else:
# 提交事务
cls.__conn.commit()
# 返回受影响的行数
return cursor.rowcount
except Exception as e:
# 事务回滚
cls.__conn.rollback()
# 打印异常信息
print(e)
finally:
# 关闭游标
cls.__close_cursor()
# 关闭连接
cls.__close_conn()
# 关闭游标
@classmethod
def __close_cursor(cls):
if cls.__cursor:
cls.__cursor.close()
cls.__cursor = None
# 关闭连接
@classmethod
def __close_conn(cls):
if cls.__conn:
cls.__conn.close()
cls.__conn = None
代码模块:test03_login_db.py
# 导包
import requests
import unittest
from api.login import LoginAPI
from tools.dbutil import DBUtil
from parameterized import parameterized
# 构造测试数据
def build_data():
sql = "select * from t_login"
db_data = DBUtil.exe_sql(sql)
print(db_data)
test_data = []
for case_data in db_data:
username = case_data[2]
password = case_data[3]
verify_code = case_data[4]
status_code = case_data[5]
content_type = case_data[6]
status = case_data[7]
msg = case_data[8]
test_data.append((username, password, verify_code, status_code, content_type, status, msg))
print("test_data = {}".format((username, password, verify_code,status_code, content_type, status, msg)))
return test_data
# 定义测试类
class TestLoginAPI(unittest.TestCase):
# 前置处理
def setUp(self):
self.login_api = LoginAPI()
self.session = requests.Session()
# 后置处理
def tearDown(self):
if self.session:
self.session.close()
# 定义测试方法
@parameterized.expand(build_data)
def test01_login(self, username, password, verify_code, status_code, content_type, status, msg):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(status_code, response.status_code)
self.assertIn(content_type, response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, username, password, verify_code)
print(response.json())
self.assertEqual(status_code, response.status_code)
self.assertEqual(status, response.json().get("status"))
self.assertIn(msg, response.json().get("msg"))
七、接口持续集成
1、持续集成概念
持续集成(Continuous Integration,简称CI)是一种软件开发实践,即团队开发成员经常集成他们的工作, 通常每个成员每天至少集成一次,也就意味着每天可能会发生多次集成。 持续集成的目的:让产品可以快速迭代,同时还能保持高质量。
2、持续集成的好处
快速发现错误:
每完成一点更新,就集成到主干,可以快速发现错误,定位错误也比较容易
防止分支大幅偏离主干:
如果不是经常集成,主干又在不断更新,会导致以后集成的难度变大,甚至难以集成
更快速的发布更新:
持续集成可以帮助团队更快速、更积极的发布程序和更新程序。在发布时可自动完成大量重复的工作、节省人力
"持续集成并不能消除Bug,而是让它们非常容易发现和改正。"
3、持续集成相关工具
Jenkins:一个开源的持续集成工具,提供软件版本发布、自动测试等一系列流程及丰富的插件
SVN/Git:源代码版本管理工具
GitHub/GitLab/Gitee:基于Git的代码仓库
4、Git
Git介绍: Git是目前世界上最先进的分布式版本控制系统
Git安装: 下载安装包,下载地址:https://git-scm.com/downloads
双击运行,然后按默认选项安装即可
校验是否安装成功,打开命令行窗口,输入命令: git --version ,看到git版本信息表示已安装成功
配置Git
安装完成后,还需要最后一步设置,在命令行输入
git config --global user.email "15708460952@163.com"
git config --global user.name "zhuwei"
git config --global --list
5、Git代码托管平台
常见的代码托管平台
Github:是一个基于git实现在线代码托管的仓库,向互联网开放,企业版要收钱国外的,受网络环境影响较大,官网:https://github.com/
Gitee:码云,是开源中国免费提供(企业版收费) 国内的,受网络环境影响较小,官网:https://gitee.com/
Gitlab:类似Github,一般用于企业内部搭建git私服
以上三种代码托管平台使用方式非常类似,受网络环境影响本课程选择Gitee(码云)来演示
1、clone仓库地址:git clone https://gitee.com/zhu-wei0915/Gitee.git
![]()
2、代码提交前先查看状态
3、添加:git add aa.py
4、提交至Git库:git commit -m "add a file"
5、拉取到远程仓库Gitee:git push
6、使用Gitee
码云Gitee是开源中国开发的一款基于Git的代码托管平台,能够实现代码托管、项目管理、协作开发等 目前是国内最大的代码系统,目前已有超过 500 万的开发者选择码云 Gitee和GitHub的作用和性质是类似的,Gitee优势是速度快
在Gitee创建项目
01、注册账号,网址:https://gitee.com/
02、点击按钮创建一个仓库
03、输入仓库名称,点击‘Create repository’按钮
04、进入仓库详情页面,点击‘克隆/下载’,再选择‘复制’即可得到项目地址
7、在PyCharm中检出Gitee中的项目
01、打开PyCharm
02、配置Git。选择菜单‘File’-->‘Settings...’,搜索git
03、选择菜单‘VCS’
04、输入项目的URL,点击Clone按钮,新建文件上传到仓库
8、Jenkins介绍
Jenkins是一个开源软件项目,是基于Java开发的一种持续集成工具,用于监控持续重复的工作, 旨在提供一个开放易用的软件平台,使软件的持续集成变成可能。
1、安装
Jenkins环境搭建
安装JDK:
版本:JDK1.8
下载地址: http://www.oracle.com/technetwork/java/javase/downloads/jdk8-downloads-2133151.html
配置环境变量: JAVA_HOME=C:\Program Files\Java\jdk1.8.0_151
在Path中添加: %JAVA_HOME%\bin;
校验:打开命令行窗口,输入java -version,校验命令能否正常执行以及版本信息是否一致
安装Jenkins:
01、下载最新的版本war包,官网:https://jenkins.io/
02、进入war包所在目录,命运行运行
java -jar jenkins.war 默认端口是8080
java –jar jenkins.war --httpPort=8888 可以用httpPort来指定端口
03、在浏览器中访问http://localhost:8080/
04、等待插件安装完成
05、安装完成后,会提示设置用户名和密码,进行后期登录使用
06、配置完成后,提示准备就绪
7、点击按钮,即可进入首页
2、系统设置
01、选择'Jenkins'->'系统管理'->'系统设置'
02、配置'系统管理员邮件地址'
03、配置'Extended E-mail Notification‘
04、配置'邮件通知
解决控制台乱码问题
01、打开系统管理->系统设置,在'全局属性'添加'环境变量'。LANG=zh_CN.UTF-8和JAVA_TOOL_OPTIONS=- Dfile.encoding=UTF8
02、启动jenkins服务的命令中指定编码 java -Dfile.encoding=UTF-8 -jar jenkins.war
邮件测试报告模板
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>${ENV, var="JOB_NAME"}-第${BUILD_NUMBER}次构建日志</title>
</head>
<body leftmargin="8" marginwidth="0" topmargin="8" marginheight="4" offset="0">
<div>
<h2>项目信息</h2>
<ul>
<li>项目名称:${PROJECT_NAME}</li>
<li>详细测试报告:<a href="${PROJECT_URL}HTML_20Report/">${PROJECT_URL}HTML_20Report/</a></li>
<li>触发原因:${CAUSE}</li>
<li>项目Url:<a href="${PROJECT_URL}">${PROJECT_URL}</a></li>
</ul>
<hr/>
<h2>构建日志</h2>
<div>${JELLY_SCRIPT,template="html"}</div>
<hr/>
</div>
</body>
</html>
9、持续集成之Postman
01、点击'New 任务'菜单
02、输入任务名称,选择'构建一个自由风格的软件项目',点击'确定’
03、任务列表,点击任务名称,进入任务操作页面
04、点击'Configure'菜单,进入任务配置页
05、添加构建,选择'执行 Windows 批处理命令',输入执行脚本:
newman run D:\postman\ihrm\ihrm.postman_collection.json -e D:\postman\ihrm\test.postman_environment.json -r html --reporter-html-export report.html
newman run D:\Gitee1\IHRM0721.postman_collection.json -e D:\Gitee1\TEST.postman_environment.json -r html --reporter-html-export report.html
06、添加构建后操作,点击‘Add post-build action’按钮,选择‘Publish HTML reports’,点击‘Add’按钮,输入配置信息
07、添加构建后操作步骤,选择'Editable Email Notification',然后配置相关信息
08、点击‘Apply’和‘Save’按钮
10、持续集成之python
01、点击'New 任务'菜单
02、输入任务名称,选择'构建一个自由风格的软件项目',点击'确定’
03、进行源码管理
04、点击'Configure'菜单,进入任务配置页
05、添加构建,选择'执行 Windows 批处理命令',输入执行脚本: python run_suite.py
06、添加构建后操作,点击‘Add post-build action’按钮,选择‘Publish HTML reports’,点击‘Add’按钮,输入配置信息
07、添加构建后操作步骤,选择'Editable Email Notification',然后配置相关信息
八、使用Flask框架mock接口
import json
from flask import Flask,request
# 创建一个应用对象
app = Flask(__name__)
# 定义视图函数,设置路由规则
@app.route("/index")
def index():
print("访问的index主页")
return "hello mock"
# {"username":"admin", "password":"123456"}
@app.route("/api/sys/login",methods=["POST"])
def login():
result = json.loads(request.get_data().decode("utf-8")) # 字典形式的请求体数据
username = result.get("username")
password = result.get("password")
print(username,password)
if username =="13800000002" and password == "123456":
data = {
"success": True, "code": 10000,
"message":"操作成功!",
"token": "ajsdfj-12312-szs-fd-dfs"
}
else:
data = {
"success": False, "code": 99999,
"message": "抱歉,系统繁忙,请稍后重试",
"token": None
}
return data
if __name__ == '__main__':
# 启动WEB服务器
app.run()