一、
requests
库
1
介绍及安装
介绍:基于
python
语言开发的一个开源的库,能够完全满足基于
HTTP
协议的接口测试。
?Requests库是用Python编写的,基于urllib,采用Apache2 Licensed开源协议的HTTP库;
相比urllib库,Requests库更加方便,可以节约我们大量的工作,完全满足HTTP测试需求;
?1.2 安装
pip install requests 安装
pip show requests 验证
2.
发送请求
常见的
HTTP
请求方式:
GET
、
POST
、
PUT
、
DELETE
使用 requests 发送网络请求非常简单,只需要调用HTTP请求类型所对应的方法即可。
发送
get
请求
# 导包
import requests
# 发送请求
response = requests.get("http://www.baidu.com")
# 查看响应
# 查看响应数据编码格式
print("原始的数据编码为:", response.encoding)
print("设置前响应数据:", response.text)
# 设置响应数据编码格式
response.encoding = "utf-8"
print("设置编码后数据编码为:", response.encoding)
print("设置后响应数据:", response.text)
请求方法的返回值
response
为
Response
对象,可以从这个对象中获取响应信息。
比 如:
response.text
可以获取响应的文本内容
?
?3 发送post请求
response = requests.post(url, data=None, json=None)
""" :param url: 请求的URL
:param data: (可选) 要发送到请求体中的字典、元组、字节或文件对象
:param json: (可选) 要发送到请求体中的JSON数据 """
data:
参数接收
form
表单数据,后台会?动附加
form
表单请求信息头(
data
数据格式为字典)
json:
参数接收
json
数据,后台会?动附加
json
表单请求信息头
(
headers = {"Content-Type":"application/json"}
)
?
3.1
提交
form
表单
"""
1. 请求TPshop项目的登录接口,
请求数据(username: 13088888888, password: 123456, verify_code: 1234)
2. 登录接口URL:http://localhost/index.php?m=Home&c=User&a=do_login
"""
# 导包
import requests
# 发请求
login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
login_data = {
"username": "13488888888",
"password": "123456",
"verify_code": "8888"
}
response = requests.post(url=login_url, data=login_data)
# 看响应
print(response.json())
?3.2 提交json数据
"""
1. 请求IHRM项目的登录接口,请求数据( {"mobile":"13800000002", "password":"123456"} )
2. 登录接口URL:http://ihrm-test.itheima.net/api/sys/login
"""
# 导包
import requests
# 发送请求
login_url = "http://ihrm-test.itheima.net/api/sys/login"
login_data = {
"mobile": "13800000002",
"password": "123456"
}
response = requests.post(url=login_url, json=login_data)
# 查看响应
print(response.json())
4 其他请求方式(了解)
put:修改资源
delete:删除资源
head:响应数据中只包含请求头,前提是项目中已实现该功能
options:查看接口支持的请求方法,前提是项目中已实现该功能
import requests
response = requests.put("http://www.baidu.com", data={"key": "value"})
response = requests.delete("http://www.baidu.com")
response = requests.head("http://www.baidu.com")
response = requests.options("http://www.baidu.com")
5
传递
URL
参数
如果需要在
URL
的查询字符串中传递数据,可以使用
params
参数来定义,
params
传递的参数可以
是字符串或字典。
response = requests.get(url, params=None)
response = requests.post(url, params=None, data=None)
# 导包
import requests
# 发送请求
# 直接通过url传递参数
# response = requests.get(" http://localhost/Home/Goods/search.html?q=iphone")
# 通过params传递参数:
# (1)字符串
urlA = "http://localhost/Home/Goods/search.html"
stringA = "q=iphone"
response = requests.get(url=urlA, params=stringA)
# (2)字典
dictA = {
"q": "iphone"
}
response = requests.get(url=urlA, params=dictA)
# 查看响应
print(response.text)
6
响应内容解析
用途:断言
实现:
response.status_code :响应状态码
response.url :url地址信息
response.encoding :查看响应数据编码格式
response.headers :查看头部信息
response.cookies : 查看cookies信息
response.text :文本形式查看响应数据
response.content :字节码形式查看响应数据
response.json() :json形式查看响应数据
7 设置请求头
?使用方法: headers={"Content-Type":"application/json"}
思考:发送
HTTP
请求时,传递参数的方式有哪些?
如果需要为请求添加请求头数据,只需要传递一个字典类型的数据给
headers
参数就可以了
"""
1. 请求IHRM项目的登录接口,URL: http://ihrm-test.itheima.net/api/sys/login
2. 请求头: Content-Type: application/json
3. 请求体: {"mobile":"13800000002", "password":"123456"}
"""
import requests
login_url = "http://ihrm-test.itheima.net/api/sys/login"
login_header = {
"Content-Type": "application/json"
}
login_data ={
"mobile": "13800000002",
"password": "123456"
}
# 发送请求
response = requests.post(url=login_url, json=login_data, headers=login_header)
# 查看响应
print(response.json())
8
设置
cookie
(了解)
产生及应用
?
获取响应信息中的
cookie
数据:
cookies = response.cookies
发送请求时添加
cookie
数据,可以使用
cookies
参数:
requests.get(url, cookies={"c1": "v1"})
?案例:解决tpshop登录验证码问题
1. 使用requests库调用TPshop登录功能的相关接口,完成登录操作
2. 登录成功后获取‘我的订单’页面的数据
接口地址:
获取验证码:http://localhost/index.php?m=Home&c=User&a=verify
登录用户:(username: 13088888888, password: 123456, verify_code: 1234)
登录:http://localhost/index.php?m=Home&c=User&a=do_login
我的订单:http://localhost/Home/Order/order_list.html
?
import requests
# 获取验证码
response = requests.get("http://localhost/index.php?m=Home&c=User&a=verify") print(response.cookies)
PHPSESSID = response.cookies.get("PHPSESSID")
print(PHPSESSID)
# 登录
login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
login_data = {
"username": "13488888888",
"password": "123456",
"verify_code": "8888" }
cookies = { "PHPSESSID": PHPSESSID }
response = requests.post(url=login_url, data=login_data, cookies=cookies)
print(response.json())
# 我的订单:http://localhost/Home/Order/order_list.html
response = requests.get("http://localhost/Home/Order/order_list.html", cookies=cookies)
print(response.text)
9
设置
session
(掌握)
作用:在多个请求之间
存储数据并自动添加数据
,如
cookies
使用:
实例化:
session = requests.Session()
发送请求:
request.get()
==>
session.get()
session对象代表一次用户会话:从客户端浏览器连接服务器开始,
到客户端浏览器与服务器断开 会话能让我们在跨请求时候保持某些参数,
比如在同一个 session 实例发出的所有请求之间保持 cookie
创建session对象
session = requests.Session()
得到session对象后,就可以调用该对象中的方法来发送请求。
import requests
# 创建session对象
session = requests.Session()
# 获取验证码
response = session.get("http://localhost/index.php?m=Home&c=User&a=verify")
# 登录
login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
login_data = {
"username": "13488888888",
"password": "123456",
"verify_code": "8888" }
response = session.post(url=login_url, data=login_data)
print(response.json())
# 我的订单:http://localhost/Home/Order/order_list.html
response = session.get("http://localhost/Home/Order/order_list.html")
print(response.text)
二、集成
UnitTest
将接口测试脚本集成到UnitTest单元测试框架中,利用UnitTest的功能来运行接口测试用例。
1.1
使用
UnitTest
框架的目的
1.
方便管理和维护多个测试用例
2.
提供丰富的断言方法
3.
能够生成测试报告
案例:使用TPShop项目完成对登录功能的接口测试
?
获取验证码: http://localhost/index.php?m=Home&c=User&a=verify
登录 : http://localhost/index.php?m=Home&c=User&a=do_login
?实现思路:
?
# 获取验证码: http://localhost/index.php?m=Home&c=User&a=verify
# 登录 : http://localhost/index.php?m=Home&c=User&a=do_login
# 导包
import requests
import unittest
# 创建测试类
class TPShopLogin(unittest.TestCase):
def setUp(self):
# 实例化session对象
self.session = requests.Session()
# 定义验证接口url地址
self.url_verify = "http://localhost/index.php?m=Home&c=User&a=verify"
# 定义正如接口url地址
self.url_login = "http://localhost/index.php?m=Home&c=User&a=do_login"
# teardown
def tearDown(self):
# 关闭session对象
self.session.close()
# 登录成功
def test01_success(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": "13488888888",
"password": "123456",
"verify_code": "8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.json().get("status"))
self.assertIn("登陆成功", response.json().get("msg"))
# 账号不存在
def test02_user_is_not_exist(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": "13488888899",
"password": "123456",
"verify_code": "8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-1, response.json().get("status"))
self.assertIn("账号不存在", response.json().get("msg"))
# 密码错误
def test03_password_error(self):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": "13488888888",
"password": "error",
"verify_code": "8888"
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-2, response.json().get("status"))
self.assertIn("密码错误", response.json().get("msg"))
?生成报告:
# 导包
import time
import unittest
from test10_unittest_tpshop import TPShopLogin
from test12_unittest_params import TPShopLogin2
from tools.HTMLTestRunner import HTMLTestRunner
# 封装测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TPShopLogin))
suite.addTest(unittest.makeSuite(TPShopLogin2))
# 指定报告路径
report = "./report/report-{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
# 打开文件流
with open(report, "wb") as f:
# 创建HTMLTestRunner运行器
runner = HTMLTestRunner(f, title="tpshop接口测试报告")
# 执行测试套件
runner.run(suite)
实现参数化:
# 获取验证码: http://localhost/index.php?m=Home&c=User&a=verify
# 登录 : http://localhost/index.php?m=Home&c=User&a=do_login
# 导包
import json
import requests
import unittest
from parameterized import parameterized
# 构造测试数据
def build_data():
test_data = []
file = "./data/login.json"
with open(file, encoding="utf-8") as f:
json_data = json.load(f)
for case_data in json_data:
username = case_data.get("username")
password = case_data.get("password")
verify_code = case_data.get("verify_code")
status_code = case_data.get("status_code")
status = case_data.get("status")
msg = case_data.get("msg")
test_data.append((username, password, verify_code, status_code, status, msg))
print("test_data=".format(username, password, verify_code, status_code, status, msg))
return test_data
# 创建测试类
class TPShopLogin2(unittest.TestCase):
def setUp(self):
# 实例化session对象
self.session = requests.Session()
# 定义验证接口url地址
self.url_verify = "http://localhost/index.php?m=Home&c=User&a=verify"
# 定义正如接口url地址
self.url_login = "http://localhost/index.php?m=Home&c=User&a=do_login"
# teardown
def tearDown(self):
# 关闭session对象
self.session.close()
# 登录成功
@parameterized.expand(build_data())
def test01_login(self, username, password, verify_code, status_code, status, msg):
# 发送验证码请求并断言
response = self.session.get(url=self.url_verify)
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 发登录请求并断言
login_data = {
"username": username,
"password": password,
"verify_code": verify_code
}
response = self.session.post(url=self.url_login, data=login_data)
print(response.json())
self.assertEqual(status_code, response.status_code)
self.assertEqual(status, response.json().get("status"))
self.assertIn(msg, response.json().get("msg"))
一、接口测试框架开发
1
框架结构
?重点说明:
(1)核心在于将测试用例与被测试系统API进行分离,便于后期维护
(2)测试用例是通过unittest进行管理,并提供了丰富的断言(等于、包含等)
(3)可以通过参数化思想测试数据与测试脚本的分离
(4)可以调用数据库进行结果验证或将数据库作为参数化的数据源
(5)借助第三方工具快速的生成HTML报告
接口测试框架的结构说明:
API 用于封装被测系统的接口
TestCase 将一个或者多个接口封装成测试用例,并使用UnitTest管理测试用例
TestCase 可以调用数据库进行数据的校验
为了方便维护测试数据,可以把测试脚本和测试数据分离开
通过UnitTest断言接口返回的数据,并生成测试报告
2
框架目录结构
?3 封装被测试系统接口
按照功能模块定义封装被测系统的接口,方便测试脚本的调用,并且能够到达代码的复用。
对登录功能的相关接口进行封装,示例代码:
# 封装被测试系统接口
# 定义接口类
class LoginAPI:
# 初始化
def __init__(self):
self.url_verify = "http://localhost/index.php?m=Home&c=User&a=verify"
self.url_login = "http://localhost/index.php?m=Home&c=User&a=do_login"
# 获取验证码接口
def get_verify_code(self, session):
return session.get(self.url_verify)
# 登录接口
def login(self, session, username, password, verify_code):
login_data = {
"username": username,
"password": password,
"verify_code": verify_code
}
return session.post(url=self.url_login, data=login_data)
4 定义接口测试用例
将
api
模块中的一个或多个接口封装成一个测试用例,并使用测试框架
UnitTest
管理测试用例。
定义登录功能的测试用例,示例代码:
# 导包
import requests
import unittest from api.login
import LoginAPI
# 定义测试类
class TestLoginAPI(unittest.TestCase):
前置处理
def setUp(self):
self.login_api = LoginAPI()
self.session = requests.Session()
# 后置处理
def tearDown(self):
if self.session:
self.session.close()
# 定义测试方法
# 登录成功
def test01_login_success(self):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, "13488888888", "123456", "8888")
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(1, response.json().get("status"))
self.assertIn("登陆成功", response.json().get("msg"))
# 账号不正确
def test02_user_isnot_exist(self):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, "13488888899", "123456", "8888")
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-1, response.json().get("status"))
self.assertIn("账号不存在", response.json().get("msg"))
# 密码错误
def test03_password_exist(self):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(200, response.status_code)
self.assertIn("image", response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, "13488888888", "error", "8888")
print(response.json())
self.assertEqual(200, response.status_code)
self.assertEqual(-2, response.json().get("status"))
self.assertIn("密码错误", response.json().get("msg"))
?5 集成测试报告
# 导包
import time
import unittest from scripts.test01_login
import TestLoginAPI from tools.HTMLTestRunner
import HTMLTestRunner
# 封装测试套件
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLoginAPI))
# 指定报告路径
report = "./report/report-{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
# 打开文件流
with open(report, "wb") as f:
# 创建HTMLTestRunner执行器
runner = HTMLTestRunner(f, title="接口测试报告")
# 执行测试套件
runner.run(suite)
6
测试数据参数化
6.1
基于
json
文件实现参数化
# 导包
import json
import requests
import unittest from api.login
import LoginAPI from parameterized
import parameterized
# 构造测试数据
def build_data():
json_file = "../data/login.json"
test_data = []
with open(json_file, encoding="utf-8") as f:
json_data = json.load(f)
for case_data in json_data:
username = case_data.get("username")
password = case_data.get("password")
verify_code = case_data.get("verify_code")
status_code = case_data.get("status_code")
content_type = case_data.get("content_type")
status = case_data.get("status")
msg = case_data.get("msg")
test_data.append((username,
password,
verify_code,
status_code,
content_type,
status, msg))
print("test_data = {}".format((username, password, verify_code, status_code,
content_type, status, msg)))
return test_data
# 定义测试类
class TestLoginAPI(unittest.TestCase):
# 前置处理
def setUp(self):
self.login_api = LoginAPI()
self.session = requests.Session()
# 后置处理
def tearDown(self):
if self.session:
self.session.close()
# 定义测试方法
@parameterized.expand(build_data)
def test01_login(self, username, password,
verify_code, status_code, content_type, status, msg):
# 调用验证码接口
response = self.login_api.get_verify_code(self.session)
# 断言
self.assertEqual(status_code, response.status_code)
self.assertIn(content_type, response.headers.get("Content-Type"))
# 调用登录接口
response = self.login_api.login(self.session, username, password, verify_code)
print(response.json())
self.assertEqual(status_code, response.status_code)
self.assertEqual(status, response.json().get("status"))
self.assertIn(msg, response.json().get("msg"))
6.2
基于数据库实现参数化
# 1.导包
import requests
import unittest
from api.login import LoginAPI
from tools.dbutil import DBUtil
from parameterized import parameterized
# 构造数据
def build_data():
# 获取数据库的数据
sql = "select * from t_login"
db_data = DBUtil.exe_sql(sql)
test_data = []
for case_data in db_data:
username = case_data[2]
password = case_data[3]
verify_code = case_data[4]
status_code = case_data[5]
content_type = case_data[6]
status = case_data[7]
msg = case_data[8]
test_data.append((username, password, verify_code, content_type, status_code, status, msg))
print(test_data)
return test_data
# 2.创建测试类
class TestLogin(unittest.TestCase):
# 2.1 前置处理
def setUp(self):
self.login_api = LoginAPI() # 实例化接口类
self.session = requests.Session() # 创建session对象
# 2.2 后置处理
def tearDown(self):
if self.session:
self.session.close()
@parameterized.expand(build_data())
# 2.3.创建测试用例
def test01_login(self, username, password, verify_code, content_type, status_code, status, msg):
# 调用验证码接口获取验证,并进行断言
response = self.login_api.get_verify_code(self.session)
self.assertEqual(status_code, response.status_code)
self.assertIn(content_type, response.headers.get("Content-Type"))
# 调用登录接口获取登录信息,并进行断言
response = self.login_api.login(self.session, username, password, verify_code)
print(response.json())
self.assertEqual(status_code, response.status_code)
self.assertEqual(status, response.json().get("status"))
self.assertIn(msg, response.json().get("msg"))
|