接口测试postman+pytest
以下文章中涉及http协议的内容。https://blog.csdn.net/sjwnghuoyuelaiyu/article/details/155565729?spm=1011.2124.3001.6209右键后点击检查,进入开发者工具(或者F12)。以部署到本地的禅道为例,抓取登录请求,在登录前打开开发者工具。找到请求方法为post的包,点击可以查看请求报文和响应报文。查看请求头中的Cont
http协议内容
以下文章中涉及http协议的内容。
https://blog.csdn.net/sjwnghuoyuelaiyu/article/details/155565729?spm=1011.2124.3001.6209
开发者工具抓包
右键后点击检查,进入开发者工具(或者F12)。以部署到本地的禅道为例,抓取登录请求,在登录前打开开发者工具。
找到请求方法为post的包,点击可以查看请求报文和响应报文。

查看请求头中的Content-Type,可以发现提交的数据为表单数据,则可以在负载中查看:

同时查看响应头的Content-Type:为html文本格式,则可以在响应中查看文本内容:

http协议汇总

postman基本使用
向禅道发送get请求
在没有接口文档时,可以通过抓包工具来进行抓包,再通过postman来发送请求。
workspace->Collection->request,添加一个get请求,同时输入URL,由于get请求无请求体,所以请求头中无需指定Content-type,指定请求方法和URL后点击send发送请求。

向禅道发送post请求
post请求有请求体,所以在请求头中要指定Content-type,且请求体的格式依赖于指定的类型。
在登录界面用一个错误密码来登录,通过开发者工具抓取登录请求,获得URL和一些请求参数。

在postman中编辑请求。

向ihrm人力资源管理系统发送post请求:先获取报文。
然后在postman中编辑。

登录提供令牌
后续通过ihrm来进行接口测试,包含从接口测试点分析,测试用例编写与执行,接口自动化测试。
postman进阶使用
变量
变量分为全局变量(Global)、环境变量和集合变量。
全局变量
申明了全局变量后,postman中的任何集合和环境都可以使用该变量。添加全局变量如下:

环境变量
环境变量可以为不同的环境(开发,测试,生产)创建不同的环境配置,同时可以创建一些常用的变量。创建环境变量的步骤如下:

在使用变量的时候(通过{{变量名}}来使用),需要指定环境,如图:

集合变量
集合变量只能在该集合中使用,创建如下:

通过代码实现(请求前脚本)
在发送请求之前,可以通过在请求前脚本里面些内容来定义上述的三种变量,而不需要在软件内定义。
比如在某个集合里通过请求前脚本定义了一个集合变量,该变量就保存到这个集合里面,同时也可也在发送该请求之前在请求前脚本中定义,然后在URL中使用。如图:

这是因为一个请求在发送前,会先执行请求前脚本(若脚本发生错误则不会发送请求),然后发送请求,当服务器返回响应后,执行响应脚本。再举个例子,请求前脚本中定义变量账号和密码,然后在请求体中使用该变量:


发送请求之后,username和password变量也会保存到该集合中(因为定义的是集合变量)。
其余两种变量也可也通过请求前脚本来定义,具体代码如下:
pm.collectionVariables.set("URL_test","http://novel.hctestedu.com/user/login");//集合变量
pm.globals.set("URL_global1","http://novel.hctestedu.com/user/login") //全局变量
pm.environment.set("URL_login","http://novel.hctestedu.com/user/login")//环境变量
接口管理(Collection)
组织和管理API请求的容器,可以将多个请求放在一个Collection管理,可以通过集合运行器一次性执行整个Collection。如图示:

no tests found表示没有写任何断言。
断言
postman中的断言使用JavaScript编写的,分为Pre-request(请求前脚本)和Post-response(响应脚本),响应后脚本的断言包括状态码、检查某个字段等,请求前脚本可以动态设置请求头等。
postman会有些内置的断言,位置如下:

解释一下test的语法:
pm.test(参数1,参数2),test是一个测试用例,参数1是一个字符串,是这个用例的名字,第二个参数是一个函数,pm.response.to.have.status(200)链式调用检查响应状态码是否等于 200。
状态码断言
pm.test("Status code is 200", function () {
pm.response.to.have.status(200);
});
pm.test("Status is OK", function () {
pm.response.to.have.status("OK");
});
pm.test("Status code is 200 or 201", function () {
pm.expect(pm.response.code).to.be.oneOf([200,202]);
});
响应正文断言
响应体是否包含指定字符串
pm.test("Body matches string", function () {
pm.expect(pm.response.text()).to.include("SUCCESS");
});
响应体(JSON)的msg字段是否等于"SUCCESS"
pm.test("Your test name", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.msg).to.eql("SUCCESS");
});
响应体为纯文本是检查响应体是否完全相等于指定字符串
pm.test("Body is correct", function () {
pm.response.to.have.body("response_body_string");
});
同时也可检查响应体(JSON)中的某个字段是否包含(include)某个内容
pm.test("Your test name", function () {
var jsonData = pm.response.json();
pm.expect(jsonData.data.token).to.include("ey");
});
响应头断言
响应头是否包含Content-Type
pm.test("Content-Type is present", function () {
pm.response.to.have.header("Content-Type");
});
响应时间断言
响应时间是否少于200ms
pm.test("Response time is less than 200ms", function () {
pm.expect(pm.response.responseTime).to.be.below(200);
});
接口关联
上一个接口的返回数据是下一个接口的输入参数,所以这两个接口就产生了关联。实现的思路就是:
将上一个请求的响应体中用到的键保存到变量中,后续的接口就可以使用这个环境变量了。
这里以登录成功后将token保存到环境变量中为例,图示如下:

正常发送登录请求,然后在响应断言内写入上述脚本,在发送后,按照执行顺序,在发送成功之后会将token保存到环境变量中,后续就可以携带token来访问了。
这里就以读书屋为例子,我们打开个人中心并抓包,发现Cookie携带了token。

数据驱动
使用数据文件(csv、json)为一个接口提供多个测试数据,核心思想是将测试数据和测试脚本分离,并且可以提取断言。(这个功能需要破解)具体详见:
接下来是具体的操作方式,我们先编写一个csv文件,第一行为键,如图示:

在postman的数据驱动测试中,编写规则如下:
username,password,expected
user1,123,SUCCESS
user2,456,FAIL
然后在postman中编写:

这里的值为{{username}},不是我们之前设置的那些变量,而是csv文件中对应键的名字,接下来执行集合,到如下的界面后,选择文件:

同时我们也可以使用json文件,也可编写动态断言。
动态断言如下:
pm.test("验证返回的 msg 与数据文件中的预期一致", function () {
var jsonData = pm.response.json();
var expectedMsg = pm.iterationData.get("expected");
pm.expect(jsonData.msg).to.equal(expectedMsg);
});
pm.expect(实际值).to.断言方法(期望值);
pm.iterationData存储的是当前迭代对应那一行数据的所有字段。
生成测试报告
这里需要安装newman,具体参考:
首先准备集合和环境,导出集合和环境,如下图:


这里导出环境的时候要注意将变量设置为共享。
打开cmd,然后输入下面的指令发送请求:

语法:newman run 集合 (-e 环境) (-d 数据文件) (-r html --reporter-html-export 导出的html文件)
比如要将测试报告导出到桌面上的result.html中,如下:


一个登录接口实例
文件提供了测试相关结果,包含测试点分析、测试用例、生成的集合和环境、生成的测试报告。
测试点分析(ihrm)
基础内容

登录接口+添加用户

requests基本语法
发送get请求
import requests
#发送get请求
#response = requests.get(url,params,data,headers...)
#params data headers都是json格式
url="http://novel.hctestedu.com"
params={#可以加入查询参数
"name":"1",
"sex":"girl"
}
response = requests.get(url)
#(response.text)#响应内容内容 字符串
print(response.json)#解析成json格式
print(response.status_code) #状态码
print(response.reason) #状态码的描述 比如OK
print(response.headers)#响应头
print(response.cookies) #返回的cookies
get方法没有请求体,所以请求头中不需要指定Content-type。
发送post请求
import requests
#发送post请求
#表单形式
url="http://novel.hctestedu.com/user/login"
data={
"username":"123456478901",
"password":"1234567"
}
headers={
"Content-type":"application/x-www-form-urlencoded"
}
response = requests.post(url,headers=headers,data=data)
print(response.status_code)
print(response.text)
print(response.json())
Content-type默认为表单形式(application/x-www-form-urlencoded),请求数据为data,若参数为json,则默认为json格式。
#json格式
#不要同时使用 data 和 json 参数,后者会覆盖前者
json={
"username": "12345678901",
"password": "123456"
}
headers={
"Content-type":"application/json"#也可以不声明
}
response = requests.post(url,headers=headers,json=json)
print(response.status_code)
print(response.text)#只是提供演示
print(response.json())
以上为传入json文件。
#修改密码:
url="http://novel.hctestedu.com/user/updatePassword"
headers={
"content-type":"application/x-www-form-urlencoded",
"Authorization":"eyJhbGciOiJIUzUxMiJ9.eyJleHAiOjE3NzcyNjQ2MTYsInN1YiI6IntcImlkXCI6MjA0MzU3MzE4ODg3MjQzNzc2MCxcInVzZXJuYW1lXCI6XCIxODgzNDI1MDk3NFwiLFwibmlja05hbWVcIjpcIjE4ODM0MjUwOTc0XCJ9IiwiY3JlYXRlZCI6MTc3NjY1OTgxNjE3Mn0.XqMmw0bFlfeaMv5A-x348H00GqdWTZiKvPCd4t4Yd4L4zIXBs1Wta4DaF7vg8LDU3BQE3sXtsv-J_OkuI4au-A"
}
data={
"oldPassword":"1234567",
"newPassword1":"123456",
"newPassword2":"123456"
}
response = requests.post(url,headers=headers,data=data)
print(response.status_code)
print(response.text)
Restful风格修改密码时用put。
异常捕获
import requests
#表单形式
url="http://novel.hctestedu.com/user/login"
data={
"username":"12345678901",
"password":"123456"
}
headers={
"Content-type":"application/x-www-form-urlencoded"
}
try:
response = requests.post(url, headers=headers, data=data,timeout=5)
response.raise_for_status()
except requests.exceptions.Timeout:
print("Timeout")#请求超时
except requests.exceptions.RequestException as e:
print(f"请求失败{e}")
except requests.exceptions.Timeout:捕获超时异常;
except requests.exceptions.RequestException as e:捕获其他requests库产生的异常。包括 ConnectionError、HTTPError、TooManyRedirects、SSLError。
pytest+requests接口测试
结合之前学习到的pytest的内容,这里重点关注参数化,以下的类为11个测试用例的执行:
#将每个字典转换为列表在生成一个大列表
mylist=[]
for user in datas:
user_info = [] #存储username password,Vcode,expected
user_info.append(user.get("username"))
user_info.append(user.get("password"))
user_info.append(user.get("Vcode"))
user_info.append(user.get("expected"))
mylist.append(user_info)
#展开测试 参数化
#mylist 中的每个元素(通常是一个元组或列表)会被解包,其第 1 个值赋给第一个参数 username,
# 第 2 个值赋给第二个参数 password,第 3 个值赋给第三个参数 Vcode,第 4 个值赋给第四个参数 expected
class Test02():
@pytest.mark.parametrize('username,password,Vcode,expected', mylist)
def test02(self, username, password, Vcode, expected):
data={
"username": username,
"password": password,
"Vcode": Vcode
}
response = requests.post(URL, headers=headers, data=data)
assert response.status_code == 200
assert response.json().get("msg") == expected
这个项目会放在文档的开头,结合上面用postman测试的结果,要用到测试数据data11.json,可以直接调用。
这部分测试详情看下一篇文章,pytest+requests测试登录接口。
更多推荐

所有评论(0)