如何编写接口自动化框架系列之requests详解(三)

目录

1.http协议

2.requests介绍

3.requests的主要功能

3.requests的主要功能

3.1 场景1-常用方法

3.2 场景2-通用方法

3.3 场景3-cookies认证方式

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请求了 。第三方包都需要下载安装 。

下载安装 :

  1. 打开cmd窗口输入pip install requests进行安装 。

  2. 安装成功后可以进行验证 ,验证命令 :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步:

  1. 获取响应中的cookies信息 ,一般是登录成功后的cookies信息 。

  2. 将cookies信息转化为字典格式的数据 ,这个数据为了下一步使用 。

  3. 再将字典格式的cookies信息转化为cookies对象 ,然后就是登录成功后的cookies信息了 。

  4. 将登录成功后的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博客

第三、如何实现接口请求 ,并和测试用例如何对接 ,也是本篇介绍的内容。

 

  • 3
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值