python接口自动化测试之requests库详解
前言
说到python发送HTTP请求进行接口自动化测试,脑子里第一个闪过的可能就是requests库了,当然python有很多模块可以发送HTTP请求,包括原生的模块http.client,urllib2等,但由于原生的模块过于复杂,使用繁琐,那么requests库就诞生了,它也是现阶段比较流行的接口自动化测试工具之一
requests是个第三方库,封装了HTTP请求的所有方法,使用方便简单,只需要根据不同的请求方式调用相对应的方法就可以完成发送网络请求的整个过程,那么今天我们就来说说requests库是如何使用的,那么在开始之前我们大致说一下今天的主要内容:
1. requets如何发送get请求
2. requests如何发送post请求
3. params参数和data参数的区别
4. requests库中Session类的的妙用
5. 针对get请求和post请求,对requests进行简单封装
安装
通常,我们使用第三方库之前,都需要先进行安装
cmd执行命令 pip install requests 接着就可以引入该模块使用其提供的方法了
import requests
发送get请求
requests是通过调用get()方法来完成发送get请求的,那么,在掌握requests库如何发送get请求之前,你还应该简单了解一下什么是get请求,你可以参照这篇文章https://www.cnblogs.com/linuxchao/p/linuxchao-http.html
通常在我们学习一个方法如何使用之前,我们需先知道这个方法需要哪些参数?参数类型是什么? 那么我们就先分析一下get()方法的源码
def get(url, params=None, **kwargs):
r"""Sends a GET request. :param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary, list of tuples or bytes to send
in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
""" kwargs.setdefault('allow_redirects', True)
return request('get', url, params=params, **kwargs)
这就是get方法的源码了,你应该能够发现,get()方法只有一个必传的参数url,其他参数都是非必传的,那么其他的参数有什么作用呢?
params
对于这个参数,可以是字典,也可以是嵌套元组的列表,基于get请求的特点,请求参数是可以直接跟在URL之后的,以?号开始以key=value的形式传递(多个参数使用&符号进行分割),但是为了明确区分URL和参数,就需要使用params参数传递
**kwargs:其他一些关键字参数,暂时不做介绍
接下来我们来看2个简单的实例,体会一下reauets通过get()方法发送一个不带参数的get请求和带参数的请求的过程
通过get()方法发送get请求访问博客园首页
"""
------------------------------------
@Time : 2019/7/11 20:34
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests # 导入requests模块 response = requests.get('https://www.cnblogs.com/') # 发送get请求
print(response.text) # 获取响应数据
响应数据
<!DOCTYPE html>
<html lang="zh-cn">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<meta name="referrer" content="always" />
<title>博客园 - 代码改变世界</title>
<meta name="keywords" content="开发者,博客园,开发者,程序猿,程序媛,极客,编程,代码,开源,IT网站,Developer,Programmer,Coder,Geek,技术社区" />
<meta name="description" content="博客园是一个面向开发者的知识分享社区。自创建以来,博客园一直致力并专注于为开发者打造一个纯净的技术交流社区,推动并帮助开发者通过互联网分享知识,从而让更多开发者从中受益。博客园的使命是帮助开发者用代码改变世界。" />
<link rel="shortcut icon" href="//common.cnblogs.com/favicon.ico" type="image/x-icon" />
<link rel="Stylesheet" type="text/css" href="/bundles/aggsite.css?v=IlEZk4Ic2eCzcO6r0s4bGm62FAo8VZI-US_0EqUe2Bk1" />
<link id="RSSLink" title="RSS" type="application/rss+xml" rel="alternate" href="http://feed.cnblogs.com/blog/sitehome/rss" />
<script src="//common.cnblogs.com/scripts/jquery-2.2.0.min.js" type="text/javascript"></script>
<script src="/bundles/aggsite.js?v=cE0bqImLWsEG3gZXOupKxj5tj_ukK7pLeSd73DHZOT81" type="text/javascript"></script>
<script async='async' src='https://www.googletagservices.com/tag/js/gpt.js'></script>
<script>
var googletag = googletag || {};
googletag.cmd = googletag.cmd || [];
</script>
这里我只截取了一部分响应数据,响应数据其实是博客园的首页HTML源码
可以看到只需要一行代码即可完成整个请求过程,通过response.text得到响应数据(其实这个过程和我们在浏览器中输入博客园地址访问是一样的),当然你还可以使用以下的方法获取不同的响应数据
response.headers # 获取响应头信息
response.cookies # 获取返回的cookie
response.status_code # 获取状态码
发送带params参数的get请求
"""
------------------------------------
@Time : 2019/7/11 20:34
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests login_url = r'http://***/futureloan/mvc/api/member/login' # 接口地址
login_data = {"mobilephone": "", "pwd": 123456} # 接口所需参数
response = requests.get(url=login_url, params=login_data) # 发送get请求
print(response.text) # 获取响应数据
print(response.url)
响应数据
{"status":1,"code":"","data":null,"msg":"登录成功"}
http://***/futureloan/mvc/api/member/login?mobilephone=13691579841&pwd=123456
Process finished with exit code 0
我们通过传递一个字典给params参数,即可完成带参数的get请求,并获取响应数据
注意
1.我们日常工作中也最好传递字典作为接口数据,如果数据类型是json则在发送请求的时候需要先转成字典
2.只要你发送的是get请求,且不想通过url拼接的方式直接传递接口参数,那么只能使用params参数来传递(如果你使用data,json等参数时你会发现,请求并不会成功),因为通过params传递的参数会附加到url后,这也是get请求的特点,因此你需记住:发送get请求时参数只能使用params即可
以上只是简单的发送get请求的方法,至于如何发送带其他参数的get请求(比如headers,cookies等),还需对get()进一步的研究和实践
发送post请求
同样,在开始学习下面的内容之前,仍建议你先了解什么是post请求及其特点,对你学习接下来的内容也会更好理解https://www.cnblogs.com/linuxchao/p/linuxchao-http.html
requests发送post请求是通过post()方法来实现的,那么我们还是先看一下它的源码
def post(url, data=None, json=None, **kwargs):
r"""Sends a POST request. :param url: URL for the new :class:`Request` object.
:param data: (optional) Dictionary (will be form-encoded), bytes, or file-like object to send in the body of the :class:`Request`.
:param json: (optional) json data to send in the body of the :class:`Request`.
:param \*\*kwargs: Optional arguments that ``request`` takes.
:return: :class:`Response <Response>` object
:rtype: requests.Response
""" return request('post', url, data=data, json=json, **kwargs)
通过源码我们可以发现,post()和get()一样,仅有一个url参数是必传的,其他仍然可以不传递,但是其中data和json参数却是post()方法中最重要的参数,下面就说一下何时使用data,何时使用json
data
大多数post请求的接口默认支持参数类型Content-Type为application/x-www-form-urlencoded, 它告诉我们请求的接口参数需要传递一个form表单,那么我们往往是通过构造一个字典来传递form表单的,
所以当我们向服务器提交form表单时就可以使用data参数,它会接收一个字典类型的数据,存放到请求体中,然后发送给服务器(参数需是字典类型)
json
首先你访问的接口需要支持content_type为application/json格式的数据类型,那么你就可以通过json这个参数来传递接口参数(参数可以是字典也可以是json类型)
下面我们来看一个发送post请求,使用data参数的实例
"""
------------------------------------
@Time : 2019/7/12 10:22
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests login_url = r'http://***/futureloan/mvc/api/member/login' # 接口地址
login_data = {"mobilephone": "", "pwd": 123456} # 接口所需参数
response = requests.post(url=login_url, data=login_data) # 发送post请求
print(response.text) # 获取响应数据
print(response.url)
print(response.status_code)
响应数据
{"status":1,"code":"","data":null,"msg":"登录成功"}
http://***:8080/futureloan/mvc/api/member/login
200 Process finished with exit code 0
使用json参数实例
"""
------------------------------------
@Time : 2019/7/12 10:22
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests login_url = r'http://***/futureloan/mvc/api/member/login' # 接口地址
login_data = {"mobilephone": "", "pwd": 123456} # 接口所需参数
response = requests.post(url=login_url, json=login_data) # 发送post请求
print(response.text) # 获取响应数据
print(response.url)
print(response.status_code)
响应数据
{"status":0,"code":"","data":null,"msg":"手机号不能为空"}
http://***/futureloan/mvc/api/member/login
200 Process finished with exit code 0
可以看到使用data参数和json参数,获取到的返回结果是不一样的,因为我这里使用的接口不支持application/json数据格式,所以当你使用json参数传递参数时,服务器是无法解析数据的,也就不会返回正确的结果了
所以对于何时使用data参数,何时使用json参数,还需要根据实际的接口所支持的数据类型进行选择
params和data区别
上面已经说过get请求中的params参数和post请求中的data参数,那么这两个参数到底有什么区别呢?
1. 发送get请求时,由于get请求没有请求体,请求参数只能跟在url地址后的,而且服务器也只能通过解析url获得请求的参数,因此get()方法发送get请求时只能使用params参数,它会把请求的参数默认追加到url地址后面
2. 通常情况下用户需要提交某些数据时,发送的请求一般都为post请求,post请求会提交一个form表单,那么我们就可以构造一个字典格式的数据,使用data参数传递,由于post请求是有请求体的,而且请求参数就存放在请求体中,服务器也只能通过解析请求体中内容而获得请求的参数,所以post请求不能使用params传递接口参数,只能使用data,json,file等, data参数会把请求参数放到请求体中
Session类的妙用
实际工作中,我们会经常遇到需要保持某一个状态,才能测试后续的接口,比如说:充值接口,那么需要用户先登录,且一直保持登录状态才能进行充值,那么对于这种情况该怎么解决呢?这就要用到requests库中的Session类了,Session可以保持请求的状态,像我们访问某个网站一样,我们只要登录后就可以浏览该网站上的任意页面,先看下面实例
"""
------------------------------------
@Time : 2019/7/12 10:22
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests login_url = r'http://***/futureloan/mvc/api/member/login' # 登录接口地址
login_data = {"mobilephone": "", "pwd": 123456} # 接口所需参数
response_login = requests.post(url=login_url, data=login_data) # 发送post请求 登录
print(response_login.text)
recharge_url = r'http://***/futureloan/mvc/api/member/recharge' # 充值接口地址
recharge_data = {"mobilephone": "", "amount": 10000.00} # 接口所需参数
response_recharge = requests.post(url=recharge_url, data=recharge_data) # 发送请求,开始充值
print(response_recharge.text)
执行结果
{"status":1,"code":"","data":null,"msg":"登录成功"}
{"status":0,"code":null,"data":null,"msg":"抱歉,请先登录。"} Process finished with exit code 0
可以发现,我们之前都已经登录过了,但是充值时却失败了,原因就是直接使用reauests来发送请求时,并不会保持当前的状态(这也是HTTP请求的缺陷),现在我们使用Session对像再次发送充值请求,修改代码
"""
------------------------------------
@Time : 2019/7/12 10:22
@Auth : linux超
@File : requests_blog.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import requests request = requests.Session() # 初始化Session
login_url = r'http://***/futureloan/mvc/api/member/login' # 登录接口地址
login_data = {"mobilephone": "", "pwd": 123456} # 接口所需参数
response_login = request.request(method='post', url=login_url, data=login_data) # 发送post请求 登录
print(response_login.text)
recharge_url = r'http://***/futureloan/mvc/api/member/recharge' # 充值接口地址
recharge_data = {"mobilephone": "", "amount": 10000.00} # 接口所需参数
response_recharge = request.request(method='post', url=recharge_url, data=recharge_data) # 发送请求,开始充值
print(response_recharge.text)
执行结果
{"status":1,"code":"","data":null,"msg":"登录成功"}
{"status":1,"code":"","data":
{"id":5451,"regname":"test","pwd":"E10ADC3949BA59ABBE56E057F20F883E","mobilephone":"","leaveamount":"15000.00","type":"","regtime":"2019-05-26 19:08:44.0"}, "msg":"充值成功"} Process finished with exit code 0
可以发现,我们改用Session对象来发送充值请求就成功了。那这是什么原因呢?
简单来说,当我们第一次请求服务器时,获取的响应信息会包含一个set-cookie的字段,保存了我们登录的cookies信息,如果我们想保持这个状态,那么再次访问服务器时就需要带上这个cookies传递给服务器,才能保持这个状态。
那么我们使用Session对象发送请求时,Session会自动帮我们完成上述的过程,Session会自动把cookies的信息传递给服务器,而无需我们在请求参数中手动添加cookies,这样就保持了登录的状态,后续的依赖操作都可以正常执行了
reqests简单封装
有人会问,requests库已经封装的很好了,直接用就行了,为啥还要自己封装一次?
第一. 通过封装,我可以直接把所有的请求参数统一使用字典来传递
比如,我们接口请求需要的数据也就是测试数据往往会保存在excel表里面,那么我们取到后是字符串类型,字符串是无法作为请求参数传递的,所以我每次都要做数据转换,再传递给接口,为了节省这个过程,我只需要把这个过程封装到我的requests里即可,每次取数据后自动给我处理
第二. 当我想保持某个状态时,不想每次都初始化一个Session对象,那么我可以把它封装到我的requests里面,以后直接调用即可
下面来看封装的代码
"""
------------------------------------
@Time : 2019/7/12 16:14
@Auth : linux超
@File : sendrequests.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
import json
import requests class HttpRequests(object):
"""
eg: request = HttpRequests()
response = request(method, url, data)
or
response = request.send_request(method, url, data)
print(response.text)
"""
def __init__(self):
self.session = requests.Session() def send_request(self, method, url, params_type='form', data=None, **kwargs):
method = method.upper()
params_type = params_type.upper()
if isinstance(data, str):
try:
data = json.loads(data)
except Exception:
data = eval(data)
if 'GET' == method:
response = self.session.request(method=method, url=url, params=data, **kwargs)
elif 'POST' == method:
if params_type == 'FORM': # 发送表单数据,使用data参数传递
response = self.session.request(method=method, url=url, data=data, **kwargs)
elif params_type == 'JSON': # 如果接口支持application/json类型,则使用json参数传递
response = self.session.request(method=method, url=url, json=data, **kwargs)
else: # 如果接口需要传递其他类型的数据比如 上传文件,调用下面的请求方法
response = self.session.request(method=method, url=url, **kwargs)
# 如果请求方式非 get 和post 会报错,当然你也可以继续添加其他的请求方法
else:
raise ValueError('request method "{}" error ! please check'.format(method))
return response def __call__(self, method, url, params_type='form', data=None, **kwargs):
return self.send_request(method, url,
params_type=params_type,
data=data,
**kwargs) def close_session(self):
self.session.close()
try:
del self.session.cookies['JSESSIONID']
except:
pass request = HttpRequests() if __name__ == '__main__':
pass
这个封装只针对了get请求和post请求,当然你也可以把put,delete等请求添加在32行代码后面,实现更多的请求方式
解释一下30-34行代码: 这几行数据是为了把json和字符串类型的数据转换为字典的格式(通过使用字典传递接口参数)且可以处理一些特殊的形式,比如下面这样的格式
'{"mobilephone": None, "pwd": null}' # 字符串类型的,但是即不是json形式的字符串,也不是字典类型的字符串,因为字典里面没有null
封装测试
现在我们使用封装好的方法来测试一下发送登录和充值接口的请求
"""
------------------------------------
@Time : 2019/7/12 16:16
@Auth : linux超
@File : test_requests.py
@IDE : PyCharm
@Motto: Real warriors,dare to face the bleak warning,dare to face the incisive error!
@QQ : 28174043@qq.com
@GROUP: 878565760
------------------------------------
"""
from sendrequests import request
import unittest class TestRequests(unittest.TestCase): # 登录接口地址
login_url = r'http://***/futureloan/mvc/api/member/login'
# 登录接口测试数据
login_test_value = '{"mobilephone": "13691579841", "pwd": 123456}' # 充值接口地址
recharge_url = r'http://***/futureloan/mvc/api/member/recharge'
# 充值接口测试数据
recharge_test_value = {"mobilephone": "", "amount": 10000.00} def test_login_api(self):
"""登录接口测试用例"""
response = request('get', url=self.login_url, data=self.login_test_value)
self.assertTrue(response.json()["code"] == "")
print("登录接口测试通过") def test_recharge_api(self):
"""充值接口测试用例"""
response = request('get', url=self.login_url, data=self.login_test_value)
try:
# 充值接口需要先登录,才能充值
self.assertTrue(response.json()["code"] == '')
except AssertionError as e:
print('登录失败!')
raise e
else:
response = request('post', url=self.recharge_url, data=self.recharge_test_value)
self.assertTrue(response.json()["code"] == "")
print("充值接口测试通过") if __name__ == '__main__':
unittest.main()
测试结果
登录接口测试通过
..
充值接口测试通过
----------------------------------------------------------------------
Ran 2 tests in 0.570s OK Process finished with exit code 0
ok,测试代码执行通过,说明我们的封装没有啥问题, 且可以正常发送get和post请求,也可以解决测试数据问题和需要接口依赖的问题
总结
最后我们再来总结一下本文涉及到的所有的知识点和你需要掌握的
1. requests发送get请求和post请求的方法
get(url, params=None, **kwargs)
post(url, data=None, json=None, **kwargs)
2. parmas参数和data参数的区别
由于get请求无请求体,post请求有请求体
使用params参数时,默认会把参数附加到url后面,所以发送get请求时应使用params参数
使用data参数时,参数会存放到请求体中,所以发送post请求时不能使用params,应使用data,除非接口及支持get又支持post,同样get请求也不能使用data参数
3. 如何使用Seesion解决接口保持状态的问题
初始化Session实例,通过这个实例调用request()方法发送请求
4. 最重要的一个封装方法,并掌握这个封装该如何使用
主要针对get和post请求的接口
python接口自动化测试之requests库详解的更多相关文章
- python WEB接口自动化测试之requests库详解
由于web接口自动化测试需要用到python的第三方库--requests库,运用requests库可以模拟发送http请求,再结合unittest测试框架,就能完成web接口自动化测试. 所以笔者今 ...
- 接口自动化测试之-requests模块详解
一.requests背景 Requests 继承了urllib2的所有特性.Requests支持HTTP连接保持和连接池,支持使用cookie保持会话,支持文件上传,支持自动确定响应内容的编码,支持国 ...
- python接口自动化发送get请求 详解(一)
前言:接口自动化实现自动化脚本比较稳定,主要用到requests模块,后面我会把这个模块单独拉出来写一下. 一.环境安装 1.用pip安装requests模块 >>pip install ...
- Python之Unittest和Requests库详解
1.按类来执行 import unittest class f1(unittest.TestCase): def setUp(self): pass def tearDown(self): pass ...
- 接口自动化测试之HTTP协议详解
协议 简单理解,计算机与计算机之间的通讯语言就叫做协议,不同的计算机之间只有使用相同的协议才能通信.所以网络协议就是为计算机网络中进行数据交换而建立的规则,标准或约定的集合. OSI模型 1978年国 ...
- Python爬虫:requests 库详解,cookie操作与实战
原文 第三方库 requests是基于urllib编写的.比urllib库强大,非常适合爬虫的编写. 安装: pip install requests 简单的爬百度首页的例子: response.te ...
- Python爬虫学习==>第八章:Requests库详解
学习目的: request库比urllib库使用更加简洁,且更方便. 正式步骤 Step1:什么是requests requests是用Python语言编写,基于urllib,采用Apache2 Li ...
- 爬虫学习--Requests库详解 Day2
什么是Requests Requests是用python语言编写,基于urllib,采用Apache2 licensed开源协议的HTTP库,它比urllib更加方便,可以节约我们大量的工作,完全满足 ...
- requests库详解 --Python3
本文介绍了requests库的基本使用,希望对大家有所帮助. requests库官方文档:https://2.python-requests.org/en/master/ 一.请求: 1.GET请求 ...
随机推荐
- TestNG在Eclipse中运行的几种方法
目录 1 在Eclipse Outline视图中,点右键run as TestNG Test (不推荐) 2 在Eclipse类编辑界面,直接点击右键run as TestNG Test 3 通过Te ...
- 3. 源码分析---SOFARPC客户端服务调用
我们首先看看BoltClientProxyInvoker的关系图 所以当我们用BoltClientProxyInvoker#invoke的时候实际上是调用了父类的invoke方法 ClientProx ...
- Java----面向对象(继承&多态)
一.继承 什么是继承 ? 让类与类之间产生了子父类关系 ; 继承的好处是: 提高代码的复用性和维护性 java中继承的特点是: 只支持单继承.不支持多继承,但是可以多层继承; 四种权限修饰符是 : p ...
- AUTOSAR学习之RTE - 基本概念
1.什么是RTE? The Run-Time Environment (RTE) is at the heart of the AUTOSAR ECU architecture. The RTE is ...
- 头部姿态估计 - Android
概括 通过Dlib获得当前人脸的特征点,然后通过旋转平移标准模型的特征点进行拟合,计算标准模型求得的特征点与Dlib获得的特征点之间的差,使用Ceres不断迭代优化,最终得到最佳的旋转和平移参数. A ...
- python basemap readshapefile二三事
今天要用到basemap读取shp文件报错,查了很多资料,都没有解决. 先是: fig,ax = plt.subplots(figsize=(15,10)) from mpl_toolkits.bas ...
- 19 个 JavaScript 编码小技巧
这篇文章适合任何一位基于JavaScript开发的开发者.我写这篇文章主要涉及JavaScript中一些简写的代码,帮助大家更好理解一些JavaScript的基础.希望这些代码能从不同的角度帮助你更好 ...
- 802.11学习笔记1-WIFI参数含义
研究下wifi参数的含义 #The word of "Default" must not be removed Default CountryRegion= CountryRegi ...
- FutrueTask原理及源码分析
1.前言 相信很多人了解到FutureTask是因为ThreadPoolExecutor.submit方法,根据ThreadPoolExecutor.submit的使用,我们可以先猜一下FutureT ...
- Ubuntu : apt-get 命令
apt-get 命令是 Ubuntu 系统中的包管理工具,可以用来安装.卸载包,也可以用来升级包,还可以用来把系统升级到新的版本.本文介绍 apt-get 命令的基本用法,演示环境为 Ubuntu 1 ...