1.1框架结构
接口测试框架的结构如下图:
接口测试框架的结构说明:
- API 用于封装被测系统的接口
- TestCase 将一个或多个接口封装成测试用例,并使用UnitTest管理测试用例 TestCase 可以调用数据库进行数据的校验
- 为了方便维护测试数据,可以把测试脚本和测试数据分离开
- 通过UnitTest断言接口返回的数据,并生成测试报告
1.2 框架目录结构
api TestFramework # 项目名称
|- api # package:定义封装被测系统的接口
|- script # package:定义测试用例脚本
|- data # dir:存放测试数据
|- report # dir:存放生成的测试报告
|- lib # package:存放第三方的文件
|- app.py # 定义项目的配置信息
|- utils.py # 定义工具类
|- run_suite.py # 执行测试套件的入口
1.3 封装TPShop登录接口案例
按照功能模块定义封装被测系统的接口,方便测试脚本的调用,并且能够到达代码的复用。对登录功能的相关接口进行封装,示例代码:
# 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):
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)
1.4 登录测试用例
将api模块中的一个或多个接口封装成一个测试用例,并使用测试框架UnitTest管理测试用例。定义登录功能的测试用例,示例代码:
class TestLogin(unittest.TestCase):
@classmethod
def setUpClass(cls):
cla.login_api = LoginApi()
def setUp(self):
self.session = Session()
def tearDown(self):
self.session.close()
# 登录成功:到底干了些啥
# 发送请求(调api中封装的请求方法) --> 响应
# 断言
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,"17612345678","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()
# 断言
self.assertEqual(200,response.status_code)
self.assertEqual(-2,result.get("status"))
self.assertIn("密码错误",result.get("msg"))
1.5 集成测试报告
使用HTMLTestRunner生成HTML格式的测试报告
注意:需要将HTMLTestRunner.py工具放置在lib中
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)
2.参数化处理
2.1 参数化分析
1.分析需要参数化的参数,都有哪些?
输入数据:用户名,密码,验证码
预期结果:content_type,状态码,业务码,业务消息
2.2选择数据承载格式
json
db
2.3修改测试用例中的代码
1 构建参数化数据(build_data)
2 在测试用例前引用参数化(@parameter)
3 在具体的测试用例中,按照获得的数据进行参数替换
2.4构建json文件存放测试数据(例如:下图)
[
{
"username": "13012345678",
"password": "123123",
"verify_code": "8888",
"content_type":"image",
"status_code":200,
"status": 0,
"msg": "账号或密码登陆错误"
},
{
"username": "",
"password": "123123",
"verify_code": "8888",
"content_type":"image",
"status_code":200,
"status": 0,
"msg": "账号或密码登陆错误"
},
{
"username": "17688888888",
"password": "",
"verify_code": "8888",
"content_type":"image",
"status_code":200,
"status": 0,
"msg": "账号或密码登陆错误"
}
]
2.5构建参数化数据
def build_data():
with open('./data/data.json','r',encoding='utf-8') as f:
content = f.read()
data = json.loads(content)
d = []
for item in data:
d.append(
(
item["username"],
item["password"],
item["verify_code"],
item["status_code"]
item["status"],
item["msg"]
)
)
return d
2.6 测试用例实现
class TestLogin(unittest.TestCase):
# 前置处理
def setUp(self):
self.login_api = LoginAPI() #实例化接口类
self.session = requests.Session() #创建session对象
# 后置处理
def tearDown(self):
if self.session:
self.session.close()
@parameterized.expand(build_data)
# 创建测试用例
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(status_type,response.headers.get("Content-Type"))
#调用登录接口获取登录信息,并进行断言
response = self.login_api.login(self.session,username,password,verify_code)
self.assertEqual(status_code,response.status_code)
self.assertEqual(status,response.json().get("status"))
self.assertIn(msg,response.json().get("msg"))
3.db数据承载形式实现参数化
3.1 构建数据库数据
执行SQL脚本,将数据写入数据库中
3.2 修改构建数据函数
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]
content_type = case_data[5]
status_code= case_data[6]
status = case_data[7]
msg = case_data[8]
test_data.append(
(
username,password,verify_code,content_type,status_code,status,msg
)
)
return test_data