目录
1.http协议
2.requests介绍
3.requests的主要功能
3.requests的主要功能
3.1 场景1-常用方法
3.2 场景2-通用方法
4.requests 在项目中的实践
4.1 在接口层实现一个接口
4.2 在测试用例层调用
4.3 项目总结
本文是接口自动化测试框架系列篇的第三篇 ,主要介绍requests包 ,这个包在实现接口自动化框架中基本是一个必备包 。只要你使用python去编写接口自动化框架 ,这个包是你要必须掌握的 。
1.http协议
1.为什么要理解http协议
本篇幅虽然在介绍requests这个三方包 ,但是只要提到这个包 ,你就不得不先去了解下http协议 。为什么 ?
因为requests就是专门用于实现http协议的一个python第三方包 ,它里面的功能几乎都是围绕着http协议里面去实现的 ,所以提前理解http协议有助于我们更好的学习requests包 。
当然你也可能会问 ? 为什么我们要学习http协议 ,http协议跟我们做接口测试有什么关系 ? 跟我们做接口自动化框架有什么关系 ?答案也很简单 ,因为http协议是目前使用最为广泛的一种传输协议 ,我们经常说的上网 ,访问的页面、看的视频 、图片等等,几乎都是通过http协议实现的 。当然公司产品所实现的接口也多是基于http协议开发的 ,既然你要做接口测试 ,所用工具也好、代码也好,就必须遵循http协议的规则。requests就是这样一个工具包 ,来用于实现http协议的一些规则 ,通过使用它就能请求http协议类型的接口,从而完成接口测试和接口自动化。
2.http协议介绍
HTTP :超文本传输协议(英文:HyperText Transfer Protocol,缩写:HTTP)是一个基于请求与响应模式的应用层协议,它目前也是互联网中使用最为广泛的一种协议 。
它是一种基于请求-响应的模式,请求从客户端发出,最后服务器端响应该请求并返回,换句话说,肯定是先从客户端开始建立通信的,服务器端在没有 接收到请求之前不会发送响应。
3.http协议的组成
上面的介绍可以看到 ,一个http数据包其实就包括了一个请求和一个响应 ,而具体细化有可以包括如下 :
4.抓包查看
我们也知道 ,像http这样的数据包 ,通过抓包查看是最方便的 ,我这里就选取使用fiddler进行抓包查看,就以禅道官网的登录为例,具体地址为:
通过这个实际的数据包 ,你是否会更容易理解它的组成呢 ?当然我们后面要做的http接口测试 ,也是这样的组成 。所以 ,理解一个数据包对我们来说很重要 。
5.接口主要组成
虽然从上面的一个数据包可以看到 ,无论是请求还是响应 ,具体里面的内容都很多 ,那么这些内容都需要我们理解吗 ?答案是不需要 。我们只需要关注如下内容就可以做接口测试了 。
请求:
主要元素 | 位置 | 说明 | 包含 |
---|---|---|---|
请求方法 | 第一行的第一个关键字 | 属于请求行,包含多个方法,其中后面的四个方法最常用 | get : 向服务器查询资源 post :向服务器提交资源 delete : 向服务器删除资源 put : 向服务器修改资源 |
请求地址 | 第一行的第二部分 | 属于请求行,这个就是URL地址,浏览器地址栏中输入的地址就是这个 | |
Content-Type | 请求头中找Content-Type的关键字 | 属于请求头,包含多个值 ,其中最多的是后面的两个值 | application/json:代表请求体中的数据类型为JSON格式 application/x-www-form-urlencode:代表请求体的数据类型为表单。 |
请求体 | 请求体的整个部分,一般是请求中的最后一行 | 属于请求体 ,这里主要看格式,具体格式可参考Content-Type的值 | JSON编写格式 :{key1:value1,key2:value2,...} 表单格式 : key1=value&key2=value2&... |
其中上面的数据包截图,就是表单格式 ,这个就可以通过Content-Type查看 。
响应:
主要元素 | 位置 | 说明 | 包含 |
---|---|---|---|
状态码 | 响应中第一行的第2部分的那个数字 | 属于响应行,这个状态有很多,后面的可以记一下 | 200 OK: 表示访问成功。抓包抓到的大部分结果都是 200 404 Not Found:没有找到资源。URL 标识的资源不存在, 那么就会出现 404 403 Forbidden: 表示访问被拒绝。有的页面通常需要用户具有一定的权限才能访问(登陆后才能访问).。如果用户没有登陆直接访问, 就容易见到 403 500 Internal Server Error: 服务器出现内部错误. 一般是服务器的代码执行过程中遇到了一些特殊情况(服务器异常崩溃)会产生这个状态码 302 Move temporarily:临时重定向。在登陆页面中经常会见到 302. 用于实现登陆成功后自动跳转到主页 |
响应体 | 响应中的最后一部分 | 属于响应体 ,响应体是一个整体,一般都是一个json体 | 我们所测试的接口返回值就在这个json体里 。 |
简单的总结下 ,一个http的请求和响应都包含很多内容 ,但是对于做接口测试来说 ,我们无需关注那么多 ,知道以下部分即可。
请求:
(1)请求方法 :get方法、post方法、put方法、delete方法
(2)请求地址 :就是浏览器地址栏里输入的那个地址
(3)请求头: 主要看Centent-Type这个字段
(4)请求体 : 主要有两种格式 ,JSON和表单 ,它们的编码方式不同 。
响应:
(1)状态码 :200,302,400,404,500
(2)响应体 :接口返回的结果就在这里面 ,一般都是json格式。
2.requests介绍
requests是一个python的第三方包 ,主要用例实现基于http的请求和响应,其特点就是安全、简单 ,通过它就可以使用python去调用一个http请求了 。第三方包都需要下载安装 。
下载安装 :
-
打开cmd窗口输入
pip install requests
进行安装 。 -
安装成功后可以进行验证 ,验证命令 :
pip show requests
,显示版本和名字即安装成功 。
使用时需要先导入,导入命令:
import requests
3.requests的主要功能
3.requests的主要功能
3.1 场景1-常用方法
对我们来说,肯定是从最常见、最常用的功能里说起 。这些方法足以满足我们的接口测试需求 ,当然使用它还能进行爬虫等操作 。因为都是为了实现http协议 ,所以你几乎能看到它们的对应关系 。具体如下 :
通过上图可以看出 ,requests包分别有处理请求的方法、也有处理响应的方法,当然也并仅仅只是这些方法,只是这些是最常用的,具体为 :
1.get方法
"""
get(url,headers) : 实现http协议中的get请求 。
"""
# 需求 : 请求百度
# 1. 导包
import requests
# 2. 请求
res = requests.get("http://www.baidu.com")
# 3. 查看响应结果
print(res.text)
2.post方法-表单请求
"""
post(url,data,json) :
请求地址 : url
请求体 :
data :可以接受任何数据类型 ,默认的是表单 ,要求数据格式 : 字典 ,元组 ,文件对象,字节 。
json : 只接受的是JSON数据 ,数据格式是:字典格式 。
"""
"""
需求:
1. 请求xx项目的登录接口,请求数据(username: 15012345678, password: 123456)
2. 登录接口URL:http://localhost/index.html?a=do_login
"""
# 1. 导包
import requests
# 2. 请求接口
login_url = "http://localhost/index.html?a=do_login"
login_data = {"username":"15012345678","password":"123456"}
res = requests.post(login_url,data=login_data)
# 3. 查看结果
print(res.text)
3.post方法-JSON格式
"""
post(url,data,json) :
请求地址 : url
请求体 :
data :可以接受任何数据类型 ,默认的是表单 ,要求数据格式 : 字典 ,元组 ,文件对象,字节 。
json : 只接受的是JSON数据 ,数据格式是:字典格式 。
"""
"""
需求:
1. 请求xx项目的登录接口,请求数据(username: test001, password: test001)
2. 登录接口URL:http://localhost:8080/admin/auth/login
"""
# 1. 导包
import requests
# 2. 请求接口
login_url = "http://localhost:8080/admin/auth/login"
login_data = {"username":"test001","password":"test001"}
res = requests.post(login_url,json=login_data)
# 3. 查看结果
print(res.text)
注意 :以上的这个案例和第2个案例的区别就在于传递请求体的参数名不同,第2个案例传递的是data,而第3个传递的是json 。
4.属性介绍
# 查看响应内容
"""
案例
1. 访问百度首页的接口 http://www.baidu.com ,获取以下响应数据
2. 获取响应状态码
3. 获取请求URL
4. 获取响应字符编码
5. 获取响应头数据
6. 获取文本形式的响应内容
"""
# 1. 导包
import requests
# 2. 请求百度
response = requests.get("http://www.baidu.com")
print(response)
response.encoding = 'utf-8'
# 3 输出主要信息
print("查看响应状态码:",response.status_code)
print("查看请求地址url:",response.url)
print("查看响应的字符编码:",response.encoding)
print("查看响应头地址:",response.headers)
print("查看响应体的文本信息:",response.text)
5.json()方法
"""
json() : 获取响应为JSON格式的数据 ,若不是JSON格式,就会报错 。
"""
"""
案例
1). 访问查询天气信息的接口,并获取JSON响应数据 2). 接口地址:http://www.weather.com.cn/data/sk/101010100.html
"""
import requests
response = requests.get("http://www.weather.com.cn/data/sk/101010100.html")
response.encoding = 'utf-8'
result = response.json()
print(result)
# 获取city的值
result = result.get('weatherinfo').get('city')
print(result)
3.2 场景2-通用方法
下面的这个方法比较万能 ,因为这个方法相当于实现了所有的请求方法 ,比如包括get请求、post请求、put请求、delete请求等。
以下这是源代码中的介绍 :
def request(self, method, url,
params=None, data=None, headers=None, cookies=None, files=None,
auth=None, timeout=None, allow_redirects=True, proxies=None,
hooks=None, stream=None, verify=None, cert=None, json=None):
"""Constructs a :class:`Request <Request>`, prepares it and sends it.
Returns :class:`Response <Response>` object.
:param method: method for the new :class:`Request` object.
:param url: URL for the new :class:`Request` object.
:param params: (optional) Dictionary or bytes to be sent in the query
string for the :class:`Request`.
:param data: (optional) Dictionary, list of tuples, bytes, or file-like
object to send in the body of the :class:`Request`.
:param json: (optional) json to send in the body of the
:class:`Request`.
:param headers: (optional) Dictionary of HTTP Headers to send with the
:class:`Request`.
:param cookies: (optional) Dict or CookieJar object to send with the
:class:`Request`.
:param files: (optional) Dictionary of ``'filename': file-like-objects``
for multipart encoding upload.
:param auth: (optional) Auth tuple or callable to enable
Basic/Digest/Custom HTTP Auth.
:param timeout: (optional) How long to wait for the server to send
data before giving up, as a float, or a :ref:`(connect timeout,
read timeout) <timeouts>` tuple.
:type timeout: float or tuple
:param allow_redirects: (optional) Set to True by default.
:type allow_redirects: bool
:param proxies: (optional) Dictionary mapping protocol or protocol and
hostname to the URL of the proxy.
:param stream: (optional) whether to immediately download the response
content. Defaults to ``False``.
:param verify: (optional) Either a boolean, in which case it controls whether we verify
the server's TLS certificate, or a string, in which case it must be a path
to a CA bundle to use. Defaults to ``True``. When set to
``False``, requests will accept any TLS certificate presented by
the server, and will ignore hostname mismatches and/or expired
certificates, which will make your application vulnerable to
man-in-the-middle (MitM) attacks. Setting verify to ``False``
may be useful during local development or testing.
:param cert: (optional) if String, path to ssl client cert file (.pem).
If Tuple, ('cert', 'key') pair.
:rtype: requests.Response
"""
可以看到 ,这个方法接受的主要参数有:
-
method : 传递请求方法,比如get、post、delete、put等
-
url : 传递url
-
params : 传递查询参数 ,即url里最后的哪一部分 。
-
data : 传递请求体数据 ,表单或json格式数据都可以
-
headers :传递请求头数据
-
cookies : 传递cookies数据
-
files:支持上传文件
-
json :传递请求体数据 ,只支持json格式数据 。
这个方法对我们做接口测试有什么用呢 ?最大的好处就是将所有的测试用例写成配置文件一次性都传递进去,循环请求 。最终编写的测试用例都变成这样的配置文件了 ,无需再维护接口层 ,测试人员只是添加这样的用例文件即可了 ,大大减轻了工作量 。这就是所谓的基于配置的接口自动化框架
3.3 场景3-cookies认证方式
目前多数项目的认证方式都是通过token去认证 ,即请求登录接口给返回个token值,后面的接口再请求只需带上这个token值就可以了 。这种处理方式在我们上面讲的场景1就能搞定 ,这里就不再赘述 。
但是还有一些项目的认证方式是通过cookies去认证 ,就是将认证信息保存在了响应头中的cookies中 ,在代码中处理一般就是4步:
-
获取响应中的cookies信息 ,一般是登录成功后的cookies信息 。
-
将cookies信息转化为字典格式的数据 ,这个数据为了下一步使用 。
-
再将字典格式的cookies信息转化为cookies对象 ,然后就是登录成功后的cookies信息了 。
-
将登录成功后的cookies信息,放在其它请求接口的cookies信息中 ,那么,这些接口就是带有了登录状态了 。
这里面关键会使用到两个方法 :
方法名 | 功能 | 说明 |
---|---|---|
requests.utils.dict_from_cookiejar(cookies) | 将cookies信息转化为字典数据 | 步骤2使用的该方法 |
requests.utils.cookiejar_from_dict(cookies) | 将字典数据转化为cookies对象 | 步骤3使用的该方法 |
代码演示:
# 1.进行登录 ,登录成功后返回response 。
response = http_api.login(Setting().login_info)
# 2.通过response.cookies获取cookies信息,然后传递给dict_from_cookiejar将其转化为字典格式的cookies 。
cookies = requests.utils.dict_from_cookiejar(response.cookies)
# 3.再次将字典格式的cookies传递给cookiejar_from_dict转化为cookies对象
cookie_jar = requests.utils.cookiejar_from_dict(cookies, cookiejar=None, overwrite=True)
# 4.将最新的cookies对象传递给reqeust方法 ,这样所有请求的接口就都带上了登录状态,从而完成了认证 。
client = requests.Session()
client.request(url,cookies=cookie_jar, **kwargs)
4.requests 在项目中的实践
需要说明的是 ,在这里暂时先不考虑封装 ,因为封装会使的代码变的复杂 。这里就是直接请求接口 。
4.1 在接口层实现一个接口
这里就以登录接口为例,文件名为:login_demo_api.py :
import requests
# 实现登录接口 ,暂时不考虑封装
def login(username,password):
login_path = 'http://localhost:8000/admin/auth/login'
login_data = {'username':username,'password':password}
response = requests.post(login_path,json=login_data) # 实现登录
result = response.json() # 返回的请求体数据以json显示
return result
4.2 在测试用例层调用
重新修改之前编写的登录测试用例 ,因为之前没有实现调用登录接口 ,这次是调用登录接口后再次进行测试 。我们编写了如下的三条
import unittest
from api.login_demo_api import login
class TestLogin(unittest.TestCase):
# case1 : 测试登录成功
def test_login_success(self):
# 实际结果 :直接调用登录接口
login_result = login('admin123','123456')
self.assertEqual(0, login_result.get('errno'))
self.assertEqual('成功', login_result.get('errmsg'))
# case2 : 测试密码错误
def test_password_is_wrong(self):
# 实际结果 :直接调用登录接口
login_result = login('admin123','abc12345')
self.assertEqual(605, login_result.get('errno'))
self.assertEqual('用户帐号或密码不正确', login_result.get('errmsg'))
# case3 : 测试密码为空
def test_password_is_null(self):
# 实际结果 :直接调用登录接口
login_result = login('admin123','')
self.assertEqual(401, login_result.get('errno'))
self.assertEqual('参数不对', login_result.get('errmsg'))
4.3 项目总结
至此,我们已经实现了三步了 ,分别是 :
第一 、如何编写一个接口自动化框架 ,在第一篇博文中介绍了 。
测试新手如何去学习接口自动化测试 ?从这一套测试框架开始 。_kele0724的博客-CSDN博客
第二、如何编写测试用例 ,已经在第二篇博文中介绍了 。如何编写接口自动化框架系列之unittest测试框架的详解(二)_kele0724的博客-CSDN博客
第三、如何实现接口请求 ,并和测试用例如何对接 ,也是本篇介绍的内容。