本文章主要讲解Python接口自动化测试的框架搭建修改,自动化测试用例设计、接口测试中用例设计的动态参数化形式等内容,本文章会跳过部分框架搭建内容,废话不多说,让我们一起来看看叭。
二、实战演练 2.1 接口介绍
我们先用一个接口为出发点,该接口为登录接口,请求方式为POST,登录后才可以进行各式各样的操作,基本信息如下所示:
按照登录接口文档,进行测试用例的设计:
测试用例属于数据,那么我们必定要读取excel,我们也有配置文件,还有日志系统,这些都属于通用内容,我们可以先将对应的代码模块添加到common中:
"""读取excel,有更简便的方法,该方法适合新手进行学习了解"""
import openpyxl
def read_excel(file_path, sheet_name):
"""读取excel中的数据"""
workbook = openpyxl.load_workbook(file_path)
sheet = workbook[sheet_name]
values = list(sheet.values)
workbook.close()
title = values[0]
rows = values[1:]
new_rows = [dict(zip(title, rows)) for rows in rows]
return new_rows
"""日志系统"""
import logging
def get_logger(logging_name="收集器",
logger_level="DEBUG",
stream_level="DEBUG",
file=None,
file_level="INFO",
fmt="%(asctime)s--%(levelname)s--%(filename)s--%(lineno)d--%(message)s"):
"""获取logger收集器"""
logger = logging.getLogger(logging_name)
logger.setLevel(logger_level)
stream_handler = logging.StreamHandler()
stream_handler.setLevel(stream_level)
logger.addHandler(stream_handler)
fmt_obj = logging.Formatter(fmt)
stream_handler.setFormatter(fmt_obj)
# 判断是否有文件,如果有,初始化file_handler,如果没有文件则不执行
if file:
file_handler = logging.FileHandler(file, encoding="utf-8")
file_handler.setLevel("INFO")
logger.addHandler(file_handler)
file_handler.setFormatter(fmt_obj)
return logger
log = get_logger()
"""yaml读取结果"""
import yaml
def read_yaml(file, encoding="utf-8"):
with open(file, encoding="utf-8") as f:
data = yaml.safe_load(f)
return data
在testcase目录下新建test_login用于测试登录并实现好excel的读取以及数据驱动,获取用例数据后我们先打印看下数据:
import unittest
import requests
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data
# 获取数据
data = read_excel(path_config.case_path, "login")
@ddt
class TestLogin(unittest.TestCase):
@list_data(data)
def test_login_success(self, case_data):
print(case_data)
补充的完整代码如下所示:
import unittest
import requests
import json
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data
# 获取数据
data = read_excel(path_config.case_path, "login")
@ddt
class TestLogin(unittest.TestCase):
@list_data(data)
def test_login_success(self, case_data):
print(case_data
"""
1、第一步得到响应数据
2、获取预期结果
3、预期结果与实际结果的对比
"""
# 把json格式的字符串转换成字典,避免在读取的时候读取的是字符串而非字典格式
json_data = json.loads(case_data["data"])
headers = json.loads(case_data["headers"])
expect = json.loads(case_data["expected"])
respon = requests.request(
method=case_data["method"],
url=case_data["Api_Url"],
json=json_data,
headers=headers
)
actual = respon.json()
self.assertEqual(actual["code"], expect["code"])
在config目录下创建setting.py,添加好对应的host域名,而后可以进行url的拼接:
# 域名
host = "http://IP:端口"
"""片段代码"""
respon = requests.request(
method=case_data["method"],
# 进行拼接,拼接前导入setting
url=setting.host + case_data["Api_Url"],
json=json_data,
headers=headers
)
除此以外我们还需要进行断言的异常捕获,再次修改后的完整代码:
import logging
import unittest
import requests
import json
from common.excel import read_excel
from config import path_config
from unittestreport import ddt, list_data
from config import setting
# 获取数据
data = read_excel(path_config.case_path, "login")
@ddt
class TestLogin(unittest.TestCase):
@list_data(data)
def test_login_success(self, case_data):
print(case_data)
"""
1、第一步得到响应数据
2、获取预期结果
3、预期结果与实际结果的对比
"""
# 把json格式的字符串转换成字典,避免在读取的时候读取的是字符串而非字典格式
json_data = json.loads(case_data["data"])
headers = json.loads(case_data["headers"])
expect = json.loads(case_data["expected"])
respon = requests.request(
method=case_data["method"],
url=setting.host + case_data["Api_Url"],
json=json_data,
headers=headers
)
actual = respon.json()
try:
self.assertEqual(actual["code"], expect["code"])
log.info(f"测试用例通过:{case_data}")
except AssertionError as err:
log.error(f"测试用例失败:{case_data},错误信息为:{err}")
# 测试用例失败捕获后,使用raise抛出
raise err
举个例子,我们在设计一个注册接口测试用例的时候,会碰到一个明显的瓶颈,该手机号是未进行注册的,在第一次执行自动化测试用例时能够成功的完成注册,但在第二次再次执行测试用例时会发现,手机号已存在,那么二次执行该测试用例就会执行失败,而面对这种情况,有以下几个解决思路:
"""
解决思路:
1、每一次通过手动的方式打开excel删除后重新输入一个新的手机号
2、在数据库中查询该手机号,如果该手机号已存在,那么在数据库进行手机号删除
3、在现有的手机号上的最末尾数+1
4、随机生成一个手机号
思路分析:
1、第一种方式虽然能够解决,但每一次执行时都需要人工手动的去替换,不便于维护
2、虽然能查询并删除手机号,但往往真实的项目不会轻易的做数据库删除操作,并且一个已注册手机号会有表关联,且大多数情况下测试无权限进行删除
3、这也是一个解决方式,我们可以在第11位数字上,每次都+1,弊端是终究会碰到可能会和其他手机号相冲突的号码从而执行失败,但效率远高于1和2
4、最后的方式也是动态参数化,在需要替换的数据上做标记,当循环遍历到这个标记时使用随机生成的号码替换这个标记,以在执行用例时能够顺利通过
"""
动态参数化就是为了解决这一类的问题,让手机号持续性的随机变更,让每一次的执行都不会因为手机号的重复而导致用例失败(使用动态参数化仍然可能会随机到已注册的号码,但概率极低),而随机生成某一个手机号码就需要用到数据伪造。
四、数据伪造在自动化测试领域中数据伪造并非是什么破坏系统安全的事情,而是希望能够自动化生成测试用例的数据且数据符合一定的规则,例如手机号,电子邮箱等等。数据伪造安可以用在自动化注册模块,也可以用于登录或其他文本输入框来检测一定的输入规则等。
在Python中进行数据伪造库 – faker库,通过pip先进行安装后即可:
import faker
# 初始化faker对象,指定生成规则区域为中国
fk = faker.Faker(locale="zh_CN")
result = fk.phone_number()
print(f"手机号:{result}")
# 随机生成一个地址
company = fk.company()
print(f"地址:{company}")
# 随机生成一个公司
address = fk.address()
print(f"公司:{address}")
# 随机生成一个城市
city = fk.city()
print(f"城市:{city}")
除了标准的伪造库能够提供伪造外,我们也可以使用自己期望的方式来制定一个规则:
def generate_new_phone():
phone = "1" + random.choice(["3", "5", "7", "8", "9"])
for i in range(9):
num = random.randint(0, 9)
phone += str(num)
return phone
print(f"函数式手机号:{generate_new_phone()}")
简易的封装伪造库函数,如果你是在框架中写数据伪造的代码,那么可以放在common中,从common中在导入以此来生成一些数据:
import faker
def generate_new_phone():
fk = faker.Faker(locale="zh_CN")
result = fk.phone_number()
return result
# 改动后的片段代码(如对片段代码有疑问,请参考前置文章):
@ddt
class TestLogin(unittest.TestCase):
@list_data(data)
def test_login_success(self, case_data):
json_data = case_data["json"]
if "#new_phone#" in json_data:
new_phone = data_forgery.generate_new_phone()
json_data = json_data.replace("#new_phone", new_phone)
本篇文章就分享到这里了,喜欢的小伙伴记得点赞收藏评论加关注哟,希望这篇文章可以帮助到正在学习自动化测试的小伙伴哟。