基于Python Requests的数据驱动的HTTP接口测试(二)

简介: 基于Python Requests的数据驱动的HTTP接口测试(二)

3 resuests对象介绍与使用


我们要是用request首先要先下载 requests,我们可以用老办法,通过pip命令下载

>pip install requests


首先我来介绍一下 requests对象的使用。


1)  通过requests发送GET请求。

response = requests.get(url,params=payload)

url为发送的地址,payload为请求的参数,格式为字典类型,前面变量名为paramsresponse为返回变量。


比如:

url =http://www.a.com/user.jsp
payload={“id”:”1”,”name”:”Tom”}
data = requests.get(url,params=payload)


2)  通过requests发送POST请求。

response = requests.post(url,data=payload)

url为发送的地址,payload为请求的参数,格式为字典类型,前面变量名为dataresponse为返回变量。

比如:

url =http://www.b.com/login.jsp
payload={“username”:”Tom”,”password”:”123456”}
data = requests.post(url,data=payload)


3)  requests的返回值

这里让我们来讨论下requests的返回值。见表1

1requests的返回值

编号

代码

解释

1

response.status_code

请求页面的状态(状态码)

2

response.headers

请求网址的headers所有信息

3

response.cookies

请求网址的cookies信息

4

response.url

请求网址的地址

5

response.history

请求的历史记录(以列表的形式显示)

6

response.text

请求网址的内容信息


在这里介绍一下请求页面的状态(状态码),这个在基于HTTP协议的接口测试中经常作为一个验证点。

  • 1XX:表示消息

这个比较少用

  • 2XX:表示成功

经常使用的是:

200:正确

  • #3XX 表示重定向.

经常使用的是:

304: 没有改变

  • 4XX 表示客户端错误

经常使用的是:

404: 网址不存在

  • 5XX6XX表示服务器错误.

经常使用的是:

500:服务器内部错误


4)有了上面这些知识,我们来看一下通过request如何来实现接口测试,我们这里以前面介绍的登录模块作为测试对象来设置测试用例。测试用例见表2


2:登录模块测试用例

编号

用户名

密码

期望结果

1

正确

错误

有提示信息“用户名或者密码错误”

2

错误

正确

有提示信息“用户名或者密码错误”

3

错误

错误

有提示信息“用户名或者密码错误”

4

正确

正确

进入登录后页面,出现“查看购物车”


假设我们的正确用户名为 jerry,正确密码为000000,这样我们设计测试代码

testLogin.py

import  requests
#正确的用户名,错误的密码
url=“http://127.0.0.1:8000/login_action/
payload={{"username":"jerry","password":“000000"}}
data =  requests.post(url,data=payload)
if  (str(data.status_code)==‘200’) and (“用户名或者密码错误” in str(data.text))
        print(“pass”)
else:
        print(“Fail”)
#错误的用户名,正确的密码
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“tom","password":“123456"}}
data =  requests.post(url,data=payload)
if  (str(data.status_code)==‘200’) and (“用户名或者密码错误” in str(data.text))
        print(“pass”)
else:
        print(“Fail”)
#错误的用户名,错误的密码
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“tom","password":“000000"}}
data =  requests.post(url,data=payload)
if  (str(data.status_code)==‘200’) and (“用户名或者密码错误” in str(data.text))
        print(“pass”)
else:
        print(“Fail”)
#正确的用户名,正确的密码
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“jerry","password":“123456"}}
data =  requests.post(url,data=payload)
if  (str(data.status_code)==‘200’) and (“查看购物车” in str(data.text))
        print(“pass”)
else:
        print(“Fail”)


这样的代码虽然可以测试,但是没有测试框架进行限制,代码不利于维护,更不利于批量地执行,我们用刚才介绍的unittest框架进行改造。


testLogin.py

import  unittest,requests
class  mylogin(unittest.TestCase):
def setUp(self):
print("--------测试开始--------")
def test_login_1:
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“tom","password":“000000"}}
data =  requests.post(url,data=payload)
self.assertEqual(‘200’,str(data.status_code))
self.assertIn((“用户名或者密码错误”,str(data.text))
def test_login_2:
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“jerry","password":“123456"}}
data =  requests.post(url,data=payload)
self.assertEqual(‘200’,str(data.status_code))
self.assertIn((“用户名或者密码错误”,str(data.text))
def test_login_3:
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“tom","password":“000000"}}
data =  requests.post(url,data=payload)
self.assertEqual(‘200’,str(data.status_code))
self.assertIn((“用户名或者密码错误”,str(data.text))
def test_login_4:
url=“http://127.0.0.1:8000/login_action/
payload={{"username":“jerry","password":“000000"}}
data =  requests.post(url,data=payload)
self.assertEqual(‘200’,str(data.status_code))
self.assertIn((“查看购物车”,str(data.text))
def tearDown(self):
print("--------测试结束--------")
if  __name__=='__main__':
#构造测试集
suite=unittest.TestSuite()
suite.addTest(mylogin("  test_login_1 "))
suite.addTest(mylogin("  test_login_2 "))
suite.addTest(mylogin("  test_login_3 "))
suite.addTest(mylogin("  test_login_4 "))
#运行测试集合
runner=unittest.TextTestRunner()
runner.run(suite)


程序通过self.assertEqual(‘200’,str(data.status_code)),来判断返回码是不是与预期的相同;通过self.assertIn((“用户名或者密码错误”,str(data.text))来判断返回的文本中是不是包括指定的字符串。测试用例test_login_1test_login_2test_login_3为错误情况的测试用来,将在返回页面中出现“用户名或者密码错误”的提示,test_login_4为正确的测试用例,登录满足需求,页面跳入到登录商品列表后页面,并且显示“查看购物车”的连接,所以我们以返回页面中是否存在“查看购物车”来判断测试是否成功。


4 数据驱动的自动化接口测试


数据驱动的自动化测试是HP在其著名的产品QTP中进行提出,并且成为了业内自动化测试的一个标准,所谓数据驱动可以理解为测试数据参数化。由于Python读取XML的技术相当成熟,我们可以把测试数据放在XML里来进行设计数据驱动的自动化接口测试。首先来看一下我是如何设计XML文件的。


loginConfig.xml

<node>
        <case>
                 <TestId>testcase001</TestId>
                 <Title>用户登录</Title>
                 <Method>post</Method>
                 <Desc>正确用户名,错误密码</Desc>
                 <Url>http://127.0.0.1:8000/login_action/</Url>
                 <InptArg>{"username":"jerry","password":"12345"}</InptArg>
                 <Result>200</Result>
                 <CheckWord>用户名或者密码错误</CheckWord>
        </case>
        <case>
                 <TestId>testcase002</TestId>
                 <Title>用户登录</Title>
                 <Method>post</Method>
                 <Desc>错误用户名,正确密码</Desc>
                 <Url>http://127.0.0.1:8000/login_action/</Url>
                 <InptArg>{"username":"smith","password":"knyzh158"}</InptArg>
                 <Result>200</Result>
                 <CheckWord>用户名或者密码错误</CheckWord>
        </case>
        <case>
                 <TestId>testcase003</TestId>
                 <Title>用户登录</Title>
                 <Method>post</Method>
                 <Desc>错误用户名,错误密码</Desc>
                 <Url>http://127.0.0.1:8000/login_action/</Url>
                 <InptArg>{"username":"smith","password":"12345"}</InptArg>
                 <Result>200</Result>
                 <CheckWord>用户名或者密码错误</CheckWord>
        </case>
        <case>
                 <TestId>testcase004</TestId>
                 <Title>用户登录</Title>
                 <Method>post</Method>
                 <Desc>正确用户名,正确密码</Desc>
                 <Url>http://127.0.0.1:8000/login_action/</Url>
                 <InptArg>{"username":"jerry","password":"knyzh158"}</InptArg>
                 <Result>200</Result>
                 <CheckWord>查看购物车</CheckWord>
        </case>
</node>


在这里<node></node>是根标识,<case>…</case>表示一个测试用例,这里面有四个<case>…</case>对,分别上述表示四个测试用例。在<case>…</case>对中,有些数据是为了我们读起来比较方便,有些数据是程序中要是用的,下面来进行分别的介绍。


  • <Desc></Desc> :测试用例描述
  • <Url></Url> :测试的URL地址(程序用到)
  • <InptArg></InptArg> :请求参数,用{}括起来,为符合Python字典格式的值参对(程序用到)
  • <Result></Result> :返回码(程序用到)
  • <CheckWord></CheckWord> :验证字符串(程序用到)


py文件中我们通过调用from xml.dom import minidom来引入minidom类;dom =  minidom.parse('loginConfig.xml')来获取所需要读取的xml文件; root = dom.documentElement来开始获取文件中节点的内容,然后通过语句aaa = root.getElementsByTagName('AAA')来获得文件中的所有叶子节点<AAA>…</AAA>对中的数据,因为文件中有多个<AAA>…</AAA>对,所以返回参数aaa为一个对象列表对,然后通过

for keyin aaa:

aaaValue = key.firstChild.data

print(aaaValue)

来获取每一个<AAA>…</AAA>对中的参数。但是由于XML文件中的标签往往不止一个,且对出现,真像我们文件所以loginConfig.xml中的<TestId><TestId><Title ><Title> <Method></Method> …,所以我们可以这样来获得。


aaa = root.getElementsByTagName('AAA')

bbb = root.getElementsByTagName('BBB')

ccc = root.getElementsByTagName('CCC')

i = 0

for keyin AAA:

aaaValue = aaa[i].firstChild.data

bbbValue = bbb[i].firstChild.data

cccValue = ccc[i].firstChild.data

print(aaaValue)

print(bbbValue)

print(cccValue)

i =i+1

我们来看一下测试代码。

loginConfig.xml


#!/usr/bin/env  python
#coding:utf-8
import  unittest,requests
from  xml.dom import minidom
class mylogin(unittest.TestCase):
        def setUp(self):
                print("--------测试结束--------")
                #从XML中读取数据
                dom =  minidom.parse('loginConfig.xml')
                root = dom.documentElement
                TestIds = root.getElementsByTagName('TestId')
                Titles =  root.getElementsByTagName('Title')
                Methods =  root.getElementsByTagName('Method')
                Descs =  root.getElementsByTagName('Desc')
                Urls = root.getElementsByTagName('Url')
                InptArgs =  root.getElementsByTagName('InptArg')
                Results =  root.getElementsByTagName('Result')
                CheckWords  =root.getElementsByTagName('CheckWord')
                i = 0
                mylists=[]
                for TestId in TestIds:
                        mydicts={}
                        #获取每一个数据,形成字典
                         mydicts["TestId"] = TestIds[i].firstChild.data
                         mydicts["Title"] = Titles[i].firstChild.data
                        mydicts["Method"]  = Methods[i].firstChild.data
                         mydicts["Desc"] = Descs[i].firstChild.data
                         mydicts["Url"] = Urls[i].firstChild.data
                         mydicts["InptArg"] = InptArgs[i].firstChild.data
                         mydicts["Result"] = Results[i].firstChild.data
                         mydicts["CheckWord"] =CheckWords[i].firstChild.data
                         mylists.append(mydicts)
                        i = i+1
                self.mylists = mylists
        def test_login(self):
                for mylist in self.mylists:
                        payload =  eval(mylist["InptArg"])
                         url=mylist["Url"]
                        #发送请求
                        try:
                                if  mylist["Method"] == "post":
                                        data  = requests.post(url,data=payload)
                                elif  mylist["Method"] == "get":
                                        data  = requests.get(url,params=payload)
                                else:
                                        print  ("Method 参数获取错误")
                        except Exception as  e:
                                 self.assertEqual(mylist["Result"],"404")
                        else:
                                 self.assertEqual(mylist["Result"],str(data.status_code))
                                 self.assertIn(mylist["CheckWord"],str(data.text))
        def tearDown(self):
                print("--------测试结束--------")
if  __name__=='__main__':
        #构造测试集
        suite=unittest.TestSuite()
         suite.addTest(mylogin("test_login"))
        #运行测试集合
        runner=unittest.TextTestRunner()
        runner.run(suite)


setUp(self)主要把XML里的所有叶子节点数据获取到,放在一个名为mylists的列表变量中,并且返回给self.mylists变量,列表中每一项为一个字典类型的数据,keyXML里的所有叶子节点标签,key所对应的值为XML标签的内容。最后self. mylists传给每个测试函数中使用。


现在我们来看一下函数test_login(self)


for mylistin self.mylists:把刚才在初始化里面定义的self.mylists每一项分别取出。

payload =eval(mylist["InptArg"]):为获取标签为InptArg中的数据,由于在XML格式定义的时候,这一项用{}括起来,里面是个值参对,由于mylist["InptArg"]返回的是一个{}括起来的具有字典格式的字符串,所以我们必须通过函数eval()进行转移成字典变量赋给payload


url=mylist["Url"]为发送HTTP的地址。


然后通过判断mylist["Method"]是等于”post”还是等于”get”,选择使用data = requests.post(url,data=payload)或者data =requests.get(url,params=payload)来发送信息,接受信息放在变量data中。


最后通过self.assertEqual(mylist["Result"],str(data.status_code))来判断返回代码是否符合期望结果,以及self.assertIn(mylist["CheckWord"],str(data.text))期望代码mylist["CheckWord"]是否在返回内容str(data.text)中来判断测试是否成功。在这里特别指出在程序中except Exception as e中通过self.assertEqual(mylist["Result"],"404")来判断是否期望结果不存在。在这个项目中我们也加上类似的runtest.py来运行所有的测试用例。格式与前面相同,再次不在重复介绍。图3是加上注册接口测试代码的测试报告。


image.png 

3基于Python RequestsHTTP接口测试报告


5 进一步优化


细心的同学可能会发现,上面程序中setUp函数我们可以进行一些封装优化,我们建立一个单独的py文件getXML.py,内容如下:

getXML.py


#!/usr/bin/env  python
#coding:utf-8
from  xml.dom import minidom
class  GetXML():
        def getxmldata(xmlfile):
                 #从XML中读取数据
                 dom =  minidom.parse(xmlfile)
                 root = dom.documentElement
                 TestIds =  root.getElementsByTagName('TestId')
                 Titles =  root.getElementsByTagName('Title')
                 Methods =  root.getElementsByTagName('Method')
                 Descs =  root.getElementsByTagName('Desc')
                 Urls = root.getElementsByTagName('Url')
                 InptArgs =  root.getElementsByTagName('InptArg')
                 Results =  root.getElementsByTagName('Result')
                 CheckWords  =root.getElementsByTagName('CheckWord')
                 i = 0
                 mylists=[]
                 for TestId in TestIds:
                         mydicts={}
                         #获取每一个数据,形成字典
                         mydicts["TestId"]  = TestIds[i].firstChild.data
                         mydicts["Title"]  = Titles[i].firstChild.data
                         mydicts["Method"]  = Methods[i].firstChild.data
                         mydicts["Desc"]  = Descs[i].firstChild.data
                         mydicts["Url"]  = Urls[i].firstChild.data
                         mydicts["InptArg"]  = InptArgs[i].firstChild.data
                         mydicts["Result"]  = Results[i].firstChild.data
                         mydicts["CheckWord"]  =CheckWords[i].firstChild.data
                         mylists.append(mydicts)
                         i = i+1
                 return mylists


这样在loginTest.py改为setUp函数只需要改为:

loginConfig.xml


from  getXML import GetXML #引入刚才建立的类
class  mylogin(unittest.TestCase):
        def setUp(self):
                print("--------测试开始--------")
                self.mylists =  GetXML.getxmldata("loginConfig.xml")#调用类中的函数
目录
相关文章
|
1月前
|
JSON Java Apache
非常实用的Http应用框架,杜绝Java Http 接口对接繁琐编程
UniHttp 是一个声明式的 HTTP 接口对接框架,帮助开发者快速对接第三方 HTTP 接口。通过 @HttpApi 注解定义接口,使用 @GetHttpInterface 和 @PostHttpInterface 等注解配置请求方法和参数。支持自定义代理逻辑、全局请求参数、错误处理和连接池配置,提高代码的内聚性和可读性。
148 3
|
14天前
|
监控 测试技术 定位技术
HTTP代理IP响应速度测试方案设计与指标体系
随着数字化发展,网络安全、隐私保护及内容访问自由成为核心需求。HTTP代理因其技术优势成为热门选择。本文介绍HTTP代理IP响应速度测试方案,包括基础性能、稳定性、地理位置、实际应用、安全性测试及监控指标,推荐测试工具,并提供测试结果评估标准。
27 2
|
2月前
|
数据采集 前端开发 算法
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
本文介绍了如何使用 Python 的 `requests` 库应对复杂的 HTTP 请求场景,包括 Spider Trap(蜘蛛陷阱)、SESSION 访问限制和请求频率限制。通过代理、CSS 类链接数控制、多账号切换和限流算法等技术手段,提高爬虫的稳定性和效率,增强在反爬虫环境中的生存能力。文中提供了详细的代码示例,帮助读者掌握这些高级用法。
127 1
Python Requests 的高级使用技巧:应对复杂 HTTP 请求场景
|
1月前
|
消息中间件 测试技术
通过轻量消息队列(原MNS)主题HTTP订阅+ARMS实现自定义数据多渠道告警
轻量消息队列(原MNS)以其简单队列模型、轻量化协议及按量后付费模式,成为阿里云产品间消息传输首选。本文通过创建主题、订阅、配置告警集成等步骤,展示了该产品在实际应用中的部分功能,确保消息的可靠传输。
44 2
|
2月前
|
JSON Java fastjson
Java Http 接口对接太繁琐?试试 UniHttp 框架吧
UniHttp 是一个声明式的 HTTP 接口对接框架,旨在简化第三方 HTTP 接口的调用过程。通过注解配置,开发者可以像调用本地方法一样发起 HTTP 请求,无需关注请求的构建和响应处理细节。框架支持多种请求方式和参数类型,提供灵活的生命周期钩子以满足复杂的对接需求,适用于企业级项目的快速开发和维护。GitHub 地址:[UniAPI](https://github.com/burukeYou/UniAPI)。
|
3月前
|
存储 JSON Go
在Gin框架中优雅地处理HTTP请求体中的JSON数据
在Gin框架中优雅地处理HTTP请求体中的JSON数据
|
2月前
|
Java 数据处理 开发者
Java Http 接口对接太繁琐?试试 UniHttp 框架~
【10月更文挑战第10天】在企业级项目开发中,HTTP接口对接是一项常见且重要的任务。传统的编程式HTTP客户端(如HttpClient、Okhttp)虽然功能强大,但往往需要编写大量冗长且复杂的代码,这对于项目的可维护性和可读性都是一个挑战。幸运的是,UniHttp框架的出现为这一问题提供了优雅的解决方案。
101 0
|
3月前
|
数据采集 JSON API
🎓Python网络请求新手指南:requests库带你轻松玩转HTTP协议
本文介绍Python网络编程中不可或缺的HTTP协议基础,并以requests库为例,详细讲解如何执行GET与POST请求、处理响应及自定义请求头等操作。通过简洁易懂的代码示例,帮助初学者快速掌握网络爬虫与API开发所需的关键技能。无论是安装配置还是会话管理,requests库均提供了强大而直观的接口,助力读者轻松应对各类网络编程任务。
127 3
|
3月前
|
机器学习/深度学习 JSON API
HTTP协议实战演练场:Python requests库助你成为网络数据抓取大师
在数据驱动的时代,网络数据抓取对于数据分析、机器学习等至关重要。HTTP协议作为互联网通信的基石,其重要性不言而喻。Python的`requests`库凭借简洁的API和强大的功能,成为网络数据抓取的利器。本文将通过实战演练展示如何使用`requests`库进行数据抓取,包括发送GET/POST请求、处理JSON响应及添加自定义请求头等。首先,请确保已安装`requests`库,可通过`pip install requests`进行安装。接下来,我们将逐一介绍如何利用`requests`库探索网络世界,助你成为数据抓取大师。在实践过程中,务必遵守相关法律法规和网站使用条款,做到技术与道德并重。
61 2
|
3月前
|
数据采集 存储 JSON
从零到一构建网络爬虫帝国:HTTP协议+Python requests库深度解析
在网络数据的海洋中,网络爬虫遵循HTTP协议,穿梭于互联网各处,收集宝贵信息。本文将从零开始,使用Python的requests库,深入解析HTTP协议,助你构建自己的网络爬虫帝国。首先介绍HTTP协议基础,包括请求与响应结构;然后详细介绍requests库的安装与使用,演示如何发送GET和POST请求并处理响应;最后概述爬虫构建流程及挑战,帮助你逐步掌握核心技术,畅游数据海洋。
77 3