文章目录
Request库
爬虫系列大量使用它
1 安装
- Requests库是用Python编写的,基于urllib,采用Apache2 Licensed开源协议的HTTP库;
- 相比urllib库,Requests库更加方便,可以节约我们大量的工作,完全满足HTTP测试需求;
pip install requests
2 使用
GET
# 导包
import requests
# 发送GET请求
response = requests.get("http://www.baidu.com")
response.text 可以获取响应的文本内容
POST
例一
import requests
# 发送POST请求
data = {"username": "13088888888", "password": "123456", "verify_code": "1234"}
response = requests.post("http://localhost/index.php?m=Home&c=User&a=do_login", data=data)
# 获取响应内容
print("text=", response.text)
例二
import requests
# 发送POST请求
data = {"mobile": "13800000002", "password": "123456"}
response = requests.post("http://182.92.81.159/api/sys/login", json=data)
# 获取响应内容
print("text=", response.text)
其他
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")
3 传递URL参数
params参数
response = requests.get(url, params=None)
import requests
# 方式一:直接定义在URL中
# response = requests.get("http://localhost/Home/Goods/search.html?q=iPhone")
# 方式二:传递字符串类型的参数
# response = requests.get("http://localhost/Home/Goods/search.html", params="q=iPhone")
# 方式三:传递字典类型的参数
response = requests.get("http://localhost/Home/Goods/search.html", params={"q": "iPhone"})
# 获取响应结果
print("url=", response.url)
4 响应内容
response是Response对象
response.status_code 状态码
response.url 请求url
response.encoding 查看响应头部字符编码
response.headers 头信息
response.cookies cookie信息
response.text 文本形式的响应内容
response.content 字节形式的响应内容
response.json() JSON形式的响应内容
如果请求响应的内容为JSON格式的数据,则可以直接调用 response.json()
方法获取数据,因为requests中内置了JSON解码器,帮助我们处理JSON数据。
json_data = response.json()
注意:如果 JSON 解码失败,response.json() 就会抛出一个异常
5 设置请求头
要传递一个字典类型的数据给 headers 参数
headers = {"area": "010"}
response = requests.get(url, headers=headers)
6 Cookie
获取响应信息中的cookie数据:
cookies = response.cookies
发送请求时添加cookie数据,可以使用cookies 参数:
requests.get(url, cookies={"c1": "v1"})
7 Session
-
session对象代表一次用户会话:从客户端浏览器连接服务器开始,到客户端浏览器与服务器断开会话能让我们在跨请求时候保持某些参数,比如在同一个 session 实例发出的所有请求之间保持cookie
-
创建session对象
session = requests.Session()
得到session对象后,就可以调用该对象中的方法来发送请求。 -
例子
import requests
# 获取验证码
session = requests.Session()
response = session.get("http://localhost/index.php?m=Home&c=User&a=verify")
print(response.cookies)
# 登录
login_data = {"username": "13012345678", "password": "123456", "verify_code": "8888"}
response = session.post("http://localhost/index.php?m=Home&c=User&a=do_login", data=login_data)
print(response.cookies)
print("login response data=", response.json())
# 我的订单
response = session.get("http://localhost/Home/Order/order_list.html")
print(response.text)
集成UnitTest
-
将接口测试脚本集成到UnitTest单元测试框架中,利用UnitTest的功能来运行接口测试用例。
-
例子
- 获取验证码:
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 TestLogin(unittest.TestCase):
def setUp(self):
self.session = requests.Session()
self.verify_url = "http://localhost/index.php?m=Home&c=User&a=verify"
self.login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
def tearDown(self):
self.session.close()
def test_login_success(self):
# 获取验证码
response = self.session.get(self.verify_url)
print("type=", response.headers.get("Content-Type"))
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
data = {"username": "13012345678", "password": "123456", "verify_code": "8888"}
response = self.session.post(self.login_url, data=data)
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(1, result.get("status"))
self.assertEqual("登陆成功", result.get("msg"))
def test_login_username_is_not_exist(self):
# 获取验证码
response = self.session.get(self.verify_url)
print("type=", response.headers.get("Content-Type"))
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
data = {"username": "13088889999", "password": "123456", "verify_code": "8888"}
response = self.session.post(self.login_url, data=data)
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-1, result.get("status"))
self.assertIn("账号不存在", result.get("msg"))
def test_login_pwd_is_error(self):
# 获取验证码
response = self.session.get(self.verify_url)
print("type=", response.headers.get("Content-Type"))
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
data = {"username": "13012345678", "password": "error", "verify_code": "8888"}
response = self.session.post(self.login_url, data=data)
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-2, result.get("status"))
self.assertIn("密码错误", result.get("msg"))
接口测试框架开发
1 框架结构
2 框架目录结构
3 封装被测系统接口
按照功能模块定义封装被测系统的接口,方便测试脚本的调用,并且能够到达代码的复用。
# api/login.py
class LoginApi:
def __init__(self):
self.verify_code_url = "http://localhost/index.php?m=Home&c=User&a=verify"
self.login_url = "http://localhost/index.php?m=Home&c=User&a=do_login"
# 获取验证码
def get_login_verify_code(self, session):
return session.get(self.verify_code_url)
# 登录
def login(self, session, username, password, verify_code):
# 发送请求
data = {
"username": username,
"password": password,
"verify_code": verify_code,
}
return session.post(self.login_url, data=data)
4 定义接口测试用例
将api模块中的一个或多个接口封装成一个测试用例,并使用测试框架UnitTest管理测试用例。
import unittest
import requests
from requests import Session
from api.login import LoginApi
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cls.login_api = LoginApi()
def setUp(self):
self.session = Session()
def tearDown(self):
self.session.close()
# 登录成功
def test_login_success(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13012345678", "123456", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(1, result.get("status"))
self.assertEqual("登陆成功", result.get("msg"))
# 账号不存在
def test_login_username_not_exist(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13088888888", "123456", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-1, result.get("status"))
self.assertIn("账号不存在", result.get("msg"))
# 密码错误
def test_login_password_is_error(self):
# 获取验证码
response = self.login_api.get_login_verify_code(self.session)
# 判断是否为图片类型
self.assertIn("image", response.headers.get("Content-Type"))
# 登录
response = self.login_api.login(self.session, "13012345678", "error", "8888")
result = response.json()
print("login response data=", result)
# 断言
self.assertEqual(200, response.status_code)
self.assertEqual(-2, result.get("status"))
self.assertIn("密码错误", result.get("msg"))
5 集成测试报告
使用HTMLTestRunner生成HTML格式的测试报告
import time
import unittest
from script.test_login import TestLogin
from tools.HTMLTestRunner import HTMLTestRunner
suite = unittest.TestSuite()
suite.addTest(unittest.makeSuite(TestLogin))
# 测试报告文件路径
report_file = "./report/report{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
with open(report_file, "wb") as f:
# 创建HTMLTestRunner运行器
runner = HTMLTestRunner(f, title="TPshop接口自动化测试报告", description="V1.0")
# 运行测试套件
runner.run(suite)
项目实战
1. 项目搭建
1.1 新建项目
项目名称:apiTestIHRM
1.2 创建目录结构
apiTestIHRM
├── api
├── script
├── data
├── report
├── lib
├── app.py
├── utils.py
└── run_suite.py
1.3 安装依赖包
安装 requests 包
安装 parameterized 包
安装 PyMySQL 包
添加 HTMLTestRunner
2. 编写代码
2.1 封装接口类
根据用例分析待测功能,按功能模块定义接口类
登录模块:login.py
员工模块:employee.py
2.2 编写测试脚本
- 定义测试脚本文件
登录模块:test_login.py
员工模块:test_employee.py
- 使用unittest管理测试脚本
2.3 执行测试脚本
- 使用unittest执行测试脚本
- 调试代码
3. 数据库数据校验
3.1 用例场景
调用修改员工信息的接口后,校验用户名是否更新到了数据库中。
3.2 表结构
CREATE TABLE `bs_user` (
`id` varchar(40) NOT NULL COMMENT 'ID',
`mobile` varchar(40) NOT NULL COMMENT '手机号码',
`username` varchar(255) NOT NULL COMMENT '用户名称',
`password` varchar(255) DEFAULT NULL COMMENT '密码',
`enable_state` int(2) DEFAULT '1' COMMENT '启用状态 0是禁用,1是启用',
`create_time` datetime DEFAULT NULL COMMENT '创建时间',
`department_id` varchar(40) DEFAULT NULL COMMENT '部门ID',
PRIMARY KEY (`id`),
UNIQUE KEY `idx_user_phone` (`mobile`) USING BTREE
) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COMMENT='员工表';
3.3示例代码
# 修改员工
def test03_update_emp(self):
# 测试数据
emp_id = TestEmployee.employee_id
username = "tom-new"
# 调用接口
response = self.employee_api.update_emp(emp_id, username)
result = response.json()
logging.info("update emp data={}".format(result))
# 断言
utils.common_assert(self, response, 200, True, 10000, "操作成功")
# 数据库数据校验
conn = pymysql.connect("182.92.81.159", "readuser", "pwd123", "ihrm")
cursor = conn.cursor()
sql = "select username from bs_user where id=%s"
cursor.execute(sql, emp_id)
data = cursor.fetchone()
db_username = data[0]
cursor.close()
conn.close()
self.assertEqual(username, db_username)
4. 测试数据参数化
4.1 定义数据文件
- 定义存放测试数据的目录,目录名称:data
- 分模块定义数据文件
登录模块:login.json
员工模块:employee.json
- 根据业务编写用例数据
4.2 引入参数化
修改测试脚本,使用 parameterized 实现参数化
5. 生成测试报告
使用 HTMLTestRunner 生成测试报告,并分析测试结果
report_file = "./report/report{}.html".format(time.strftime("%Y%m%d-%H%M%S"))
with open(report_file, "wb") as f:
runner = HTMLTestRunner(f, title="IHRM接口自动化测试报告", description="V1.0")
runner.run(suite)