一、前言
本文章主要会讲解接口自动化测试中Python如何操作数据库、为何要操作数据库,有哪些利弊,以及数据库断言、相关的接口关联的测试
二、自动化数据库理论与操作
2.1 接口自动化为何要操作数据库
接口自动化中操作数据库主要是根据业务层面决定的,部分情况例如查询手机号、或个人信息时需要操作数据库,有时候也有可能需要删除某个内容,通常而言不会这么做罢了。
2.2 接口自动化操作数据库的利弊
"""
利:
1、能够根据我们需要的业务情况来解决一定的业务问题
弊:
1、数据库的操作本身就会让自动化变得慢,需要建立连接 -- 查询 等等
2、数据库本身是一种依赖, 我们能不操作数据库尽可能不操作
"""
2.3 Python操作数据库
要操作数据库,需要先进行pymysql库的安装,按照对应语法填写好对应数据即可:
import pymysql
"""
1、连接数据库:输入用户名,密码,地址,端口
2、游标:使用游标读取数据、修改数据(执行sql语句)
3、获取操作结果
4、关闭游标
5、关闭数据库连接
"""
conn = pymysql.connect(user="future",
password="XXXXXX",
host="XX.XX.XX.XX",
port=3306
)
cursor = conn.cursor()
# 执行sql
sql = "SELECT mobile_phone,id,reg_name FROM XXXXXXX.member WHERE mobile_phone = 137XXXXXXXX"
cursor.execute(sql)
# 获取一个结果每条记录用元组表示
res = cursor.fetchone()
print(res)
# 关闭
cursor.close()
conn.close()
输出的数据是元组,元组数据不可修改,我们需要进行类型转换,如要输出字典,需要加上DictCursor:
import pymysql
from pymysql.cursors import DictCursor
"""
1、连接数据库:输入用户名,密码,地址,端口
2、游标:使用游标读取数据、修改数据(执行sql语句)
3、获取操作结果
4、关闭游标
5、关闭数据库连接
"""
conn = pymysql.connect(user="future",
password="XXXXXX",
host="XX.XX.XX.XX",
port=3306
)
cursor = conn.cursor(DictCursor)
# 执行sql
sql = "SELECT mobile_phone,id,reg_name FROM XXXXXXX.member WHERE mobile_phone = 137XXXXXXXX"
cursor.execute(sql)
# 获取一个结果每条记录用元组表示
res = cursor.fetchone()
print(res)
# 关闭
cursor.close()
conn.close()
2.4 操作数据库封装
我们需要进行函数封装,数据库内容也属于公用内容,也可以放入至common包下,函数封装后:
class DBHandler:
def __init__(self, host=setting.db_host, port=setting.db_port,
user=setting.db_user, password=setting.db_pwd):
self.conn = pymysql.connect(user=user,
password=password,
host=host,
port=port,
autocommit=True
)
def query_one(self, sql, cursor_type=DictCursor):
cursor = self.conn.cursor(cursor_type)
cursor.execute(sql)
data = cursor.fetchone()
cursor.close()
return data
def query_all(self, sql, cursor_type=DictCursor):
cursor = self.conn.cursor(cursor_type)
cursor.execute(sql)
data = cursor.fetchall()
cursor.close()
return data
def query(self, sql, one=True, cursor_type=DictCursor):
if one:
return self.query_one(sql, cursor_type)
return self.query_all(sql, cursor_type)
def close(self):
self.conn.close()
# 自己实现上下文管理器
# def __enter__(self):
# return self
#
# def __exit__(self, exc_type, exc_val, exc_tb):
# return self.close()
db_module = DBHandler()
if __name__ == '__main__':
db = DBHandler()
sql = 'select mobile_phone from futureloan.member limit 5'
res = db.query(sql, one=False)
db.close()
print(res)
#
# with DBHandler_2() as db:
# sql = 'select mobile_phone from futureloan.member limit 5'
# res = db.query(sql, one=False)
# print(res)
# 数据库配置项
db_host = "XX.XX.XX.XX"
db_port = XXXX
db_user = "future"
db_pwd = "XXXXXX"
三、校验数据库、接口关联及项目优化
自动化测试用例执行后,判断成功的测试用例才进行数据库的校验:
import unittest
import requests
import json
from common.db import DBHandler, db_module
from common.logger import log
from common.excel import read_excel
from common import helper
from config import path_config
from unittestreport import ddt, list_data
from config import setting
# 获取数据
data = read_excel(path_config.case_path , 'XXXXXX')
@ddt
class TestRegister(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
"""测试类的前置"""
cls.db = DBHandler()
@classmethod
def tearDownClass(cls) -> None:
"""测试类的前置"""
cls.db.close()
@list_data(data)
def test_register(self, case_data):
print(case_data)
json_data = case_data['json']
if '#new_phone#' in json_data:
new_phone = helper.generate_new_phone()
json_data = json_data.replace('#new_phone#', new_phone)
# 把json格式的字符串转化成字典
json_data = json.loads(json_data)
headers = json.loads(case_data['headers'])
print("替换之后", json_data)
resp = requests.request(
method=case_data['method'],
url= setting.host + case_data['url'],
json=json_data,
headers=headers
)
actual = resp.json()
print(actual)
try:
self.assertEqual(case_data['expected'], actual['code'])
except AssertionError as e:
raise e
"""
1、判断是否是注册成功的测试用例
2、查询数据库是否包含了手机号的记录
3、判断数据库记录条数是否为1
"""
if actual['msg'] == "OK":
# 通过 setUp 创建数据库连接
sql = f"select id from XXXX.XXXX where XXXXXX = {json_data['XXXXXX']}"
result = self.db.query_all(sql)
self.assertEqual(1, len(result))
往往项目中的接口都会存在接口关联,而我们就需要对接口进行单独处理:
import unittest
import requests
import json
from jsonpath import jsonpath
from decimal import Decimal
from common.db import DBHandler
from common.logger import log
from common.excel import read_excel
from common import helper
from config import path_config
from unittestreport import ddt, list_data
from config import setting
# 获取数据
from middle import api
data = read_excel(path_config.case_path , 'XXXXXX')
@ddt
class TestRecharge(unittest.TestCase):
@classmethod
def setUpClass(cls) -> None:
"""
1,访问登录接口,得到返回值
2,从返回值当中提取数据:resp["data"]["id"]
3, 从返回值当中提取数据:resp["data"]["token_info"]["token"]
4, 设置成类属性,方便测试用例函数当中调用
:return:
"""
resp_data = api.login()
# 提取方式1:
cls.member_id = resp_data["data"]["id"]
cls.token = resp_data["data"]["token_info"]["token"]
# 提取方式2:jsonpath
cls.member_id = jsonpath(resp_data, '$..id')[0]
cls.token = jsonpath(resp_data, '$..token')[0]
cls.before = jsonpath(resp_data, '$..leave_amount')[0]
# 初始化数据库
cls.db = DBHandler()
@classmethod
def tearDownClass(cls) -> None:
pass
@list_data(data)
def test_recharge(self, case_data):
"""
1, 获取 case_data 当中的数据,headers, json 是要重点关注的。
2, 数据的预处理:数据替换,数据转化成 字典格式:headers, json, expected
3, 发送请求
4, 断言
:param case_data:
:return:
"""
# 获取 case_data当中的数据,headers, json是要重点关注的。
headers_string = case_data['headers']
json_string = case_data['json']
# 数据的预处理:数据替换,数据转化成字典格式:headers, json, expected
if "#token#" in headers_string:
headers_string = headers_string.replace("#token#", self.token)
if "#member_id#" in json_string:
json_string = json_string.replace("#member_id#", str(self.member_id))
headers = json.loads(headers_string)
json_data = json.loads(json_string)
expected = json.loads(case_data['expected'])
# 获取充值之前数据库当中用户的余额
sql = f"select XXXXXXX from XXXX.XXXXX where id={self.XXXXX_id}"
before = self.db.query_one(sql)
# {"leave_amount": 200}
# 3, 发送请求
resp = requests.request(
method=case_data['method'],
url=setting.host + case_data['url'],
json=json_data,
headers=headers
)
# 4, 断言
json_response = resp.json()
try:
for key, value in expected.items():
self.assertEqual(value, json_response[key])
except AssertionError as e:
log.error(f"测试用例失败:{e}")
raise e
if json_response['msg'] == 'OK':
print(json_response)
# 通过数据库断言
sql = f"select leave_amount from futureloan.member where id={self.member_id}"
after = self.db.query_one(sql)
money = str(json_data['amount'])
after = str(after['leave_amount'])
before = str(before['leave_amount'])
self.assertEqual(Decimal(money), Decimal(after) - Decimal(before))
四、总结
关于接口自动化测试中Python如何操作数据库、为何要操作数据库,有哪些利弊,以及数据库断言、相关的接口关联的测试,笔者就说到这里了,喜欢的小伙伴可以收藏点赞评论,加关注哟,关注我每天给你不同的惊喜。
最后感谢每一个认真阅读我文章的人,礼尚往来总是要有的,虽然不是什么很值钱的东西,如果你用得到的话可以直接拿走:
这些资料,对于【软件测试】的朋友来说应该是最全面最完整的备战仓库,这个仓库也陪伴上万个测试工程师们走过最艰难的路程,希望也能帮助到你!