目录
一、接口测试
二、项目说明
三、接口测试框架结构图
四、项目功能
五、代码设计与功能说明
1、工具类分装
【软件测试|python+Pytest+Allure+Git+Jenkins接口自动化框架】2、基类分装
3、接口测试用例编写
4、Allure2测试报告
五、Jenkins集成
一、接口测试 接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为HTTP,RPC,Webservice,Dubbo,RESTful等类型。
接口测试流程
1、需求评审,熟悉业务和需求
2、开发提供接口文档
3、编写接口测试用例
4、用例评审
5、提测后开始测试
6、提交测试报告
两种常见的 HTTP 请求方法:GET 和 POST
二、项目说明 本框架是一套基于Python+Pytest+Requests+Allure+Jenkins而设计的数据驱动接口自动化测试的框架。
技术栈:
Python、Pytest、Requests、Pactverity、Excel、Json、Mysql、Allure、Logbook、Git、Jenkins
三、接口测试框架结构图
文章图片
四、项目功能 Python+Pytest+Allure+Jenkins接口自动化框架,实现Excel或Json维护测试用例,支持数据库操作,利用封装的请求基类调取相应的测试用例接口,获取配置文件中的环境地址与环境变量,
结合Pytest进行单元测试,使用LogBook进行记录日志,并生成allure测试报告,最后进行Jenkins集成项目实现集成部署,并发送测试报告邮件。
五、代码设计与功能说明
1、工具类分装 (1)log日志
项目中的log日志是logbook进行日志记录的,方便测试开发调试时进行排错纠正或修复优化。日志可选择是否打印在屏幕上即运行时是否在终端输出打印。日志格式输出可调整。
handle_log.py部分源码
def log_type(record, handler):
log = "[{date}] [{level}] [{filename}] [{func_name}] [{lineno}] {msg}".format(
date=record.time,# 日志时间
level=record.level_name,# 日志等级
filename=os.path.split(record.filename)[-1],# 文件名
func_name=record.func_name,# 函数名
lineno=record.lineno,# 行号
msg=record.message# 日志内容
)
return log
# 日志存放路径
LOG_DIR = BasePath + '/log'
print(LOG_DIR)
if not os.path.exists(LOG_DIR):
os.makedirs(LOG_DIR)
# 日志打印到屏幕
log_std = ColorizedStderrHandler(bubble=True)
log_std.formatter = log_type
# 日志打印到文件
log_file = TimedRotatingFileHandler(
os.path.join(LOG_DIR, '%s.log' % 'log'), date_format='%Y-%m-%d', bubble=True, encoding='utf-8')
log_file.formatter = log_type
# 脚本日志
run_log = Logger("global_log")
def init_logger():
logbook.set_datetime_format("local")
run_log.handlers = []
run_log.handlers.append(log_file)
run_log.handlers.append(log_std)
return ""
打印在终端的日志,如下图所示。
文章图片
同时运行项目后,会在项目文件log中自动生成一个以当天日期命名的log文件。点击log日志文件可查看日志详情即项目运行时所记录的日志或报错日志。如下图所示。
文章图片
(2)配置文件
项目中涉及到一些配置文件如username、password或环境变量时,我们可通过配置文件来获取配置值。通过配置文件中key与value的定义来确定获取配置文件的值。
handle_init.py部分源码
class HandleInit:
# 读取配置文件
def load_ini(self):
file_path = BasePath + "/config/config.ini"
cf = configparser.ConfigParser()
cf.read(file_path, encoding='UTF-8')
return cf
# 获取ini里面对应key的value
def get_value(self, key, node=None):
if node == None:
node = 'Test'
cf = self.load_ini()
try:
data = https://www.it610.com/article/cf.get(node, key)
logger.info('获取配置文件的值,node:{},key:{}, data:{}'.format(node, key, data))
except Exception:
logger.exception('没有获取到对应的值,node:{},key:{}'.format(node, key))
data = https://www.it610.com/article/None
return data
获取配置文件中的值日志如下图所示。
文章图片
(3)Api接口
获取相关测试用例及接口用例配置,记录请求相关参数的日志,定义Allure测试报告的步骤。
handle_apirequest.py部分代码
class ApiRequest:
def api_request(self, base_url, test_case_data, case_data):
get_name = None
get_url = None
get_method = None
get_headers = None
get_cookies = None
get_case_name = None
get_case_params = None
response_data = https://www.it610.com/article/None
try:
get_name = test_case_data['config']['name']
get_url = base_url + test_case_data['config']['url']
get_method = test_case_data['config']['method']
get_headers = test_case_data['config']['headers']
get_cookies = test_case_data['config']['cookies']
except Exception as e:
logger.exception('获取用例基本信息失败,{}'.format(e))
try:
get_case_name = case_data['name']
get_case_params = case_data['params']
except Exception as e:
logger.exception('获取测试用例信息失败,{}'.format(e))
with allure.step("请求接口:%s,请求地址:%s,请求方法:%s,请求头:%s,请求Cookies:%s" % (
get_name, get_url, get_method, get_headers, get_cookies)):
allure.attach("接口用例描述:", "{0}".format(get_case_name))
allure.attach("接口用例请求参数:", "{0}".format(get_case_params))
logger.info(
'请求接口名:%r,请求地址:%r,请求方法:%r,请求头:%r,请求Cookies:%r' %\ (get_name, get_url, get_method, get_headers, get_cookies))
logger.info('请求接口名:%r,请求接口用例名:%r,接口用例请求参数:%r' %\ (get_name, get_case_name, get_case_params))
try:
(4)Excel数据处理
Excel测试用例
文章图片
测试用例中维护在Excel文件中,类中定义如何获取Excel中的相关数据(如获取某个单元格的内容,获取单元格的行数,以及将数据写入Excel中等操作)。
handle_exceldata.py部分源码
1 class OperationExcel:
2def __init__(self, file_name=None, sheet_id=None):
3if file_name:
4self.file_name = file_name
5self.sheet_id = sheet_id
6else:
7self.file_name = ''
8self.sheet_id = 0
9self.data = https://www.it610.com/article/self.get_data()
10
11# 获取sheets的内容
12def get_data(self):
13data = xlrd.open_workbook(self.file_name)
14tables = data.sheets()[self.sheet_id]
15return tables
16
17# 获取单元格的行数
18def get_lines(self):
19tables = self.data
20return tables.nrows
21
22# 获取某一个单元格的内容
23def get_cell_value(self, row, col):
24return self.data.cell_value(row, col)
(5)Json数据处理
Json测试用例
1{
2"config":{
3"name":"post接口名",
4"url":"/langdetect",
5"method":"POST",
6"headers":{
7"Content-Type":"application/json"
8},
9"cookies":{
10
11}
12},
13"testcase":[
14{
15"name":"测试用例1",
16"params":{
17"query":"测试"
18},
19"validate":[
20{
21"check":"status_code",
22"comparator":"eq",
23"expect":"200"
24}
25]
26},
27{
28"name":"测试用例2",
29"params":{
30"query":"python"
31},
32"validate":[
33{
34"check":"msg",
35"comparator":"eq",
36"expect":"success"
37}
38]
39}
40]
41 }
Json用例处理
获取Json文件中里具体字段的值。
handle.json.py部分源码
1 class HandleJson:
2# 读取json文件
3def load_json(self, file_name):
4if file_name == None:
5file_path = ""
6else:
7file_path = file_name
8try:
9with open(file_path, encoding='UTF-8') as f:
10data = https://www.it610.com/article/json.load(f)
11return data
12except Exception:
13print("未找到json文件")
14return {}
15
16# 读取json文件里具体的字段值
17def getJson_value(self, key, file_name):
18if file_name == None:
19return ""
20jsonData = https://www.it610.com/article/self.load_json(file_name)
21if key == None:
22getJsonValue =""
23else:
24getJsonValue = https://www.it610.com/article/jsonData.get(key)
25return getJsonValue
2、基类分装 1、请求基类分装
接口支持Get、Post请求,调用requests请求来实现接口的调用与返回。接口参数包括,接口地址、接口请求参数、cookie参数、header参数。
1 class BaseRequest:
2
3def send_get(self, url, data, header=None, cookie=None):
4"""
5Requests发送Get请求
6:param url:请求地址
7:param data:Get请求参数
8:param cookie:cookie参数
9:param header:header参数
10"""
11response = requests.get(url=url, params=data, cookies=cookie, headers=header)
12return response
13
14def send_post(self, url, data, header=None, cookie=None):
15"""
16Requests发送Post请求
17:param url:请求地址
18:param data:Post请求参数
19:param data:Post请求参数
20:param cookie:cookie参数
21:param header:header参数
22"""
23response = requests.post(url=url, json=data, cookies=cookie, headers=header)
24return response
25
26# 主函数调用
27
28def run_main(self, method, url, data, header, cookie=None):
29try:
30result = ''
31if method.upper() == 'GET':
32result = self.send_get(url, data, header, cookie)
33elif method.upper() == 'POST':
34result = self.send_post(url, data, header, cookie)
35return result
36except Exception as e:
37logger.exception('请求主函数调用失败:{}'.format(e))
3、接口测试用例编写 (1)引用Pytest来进行接口的单元测试,通过JSON中多个测试用例来做为参数化数据驱动。结合Allure制定相应接口的测试报告。在接口返回断言之前,我们先进行该接口的契约测试,
我们采用的是Pactverity的全量契约校验测试。当契约测试通过时,我们再进行返回参数的相关校验测试。
test_getRequestJson.py部分源码
1 @allure.feature('测试GET请求模块')
2 class TestRequestOne():
3@allure.title('测试标题')
4@allure.testcase('测试地址:https://www.imooc.com')
5@pytest.mark.parametrize('case_data', testCaseData['testcase'])
6def test_requestOne(self, case_data):
7try:
8api_response = apiRequest.api_request(baseurl, testCaseData, case_data)
9api_response_data = https://www.it610.com/article/api_response.json()
10# pactverity——全量契约校验
11config_contract_format = Like({
12"msg": "成功",
13"result": 0,
14"data": EachLike({
15"word": Like("testng")
16})
17})
18mPactVerify = PactVerify(config_contract_format)
19try:
20mPactVerify.verify(api_response_data)
21logger.info(
22'verify_result:{},verify_info:{}'.format(mPactVerify.verify_result, mPactVerify.verify_info))
23assert mPactVerify.verify_result == True
24except Exception:
25err_msg = '契约校验错误'
26logger.exception('测试用例契约校验失败,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,
27mPactVerify.verify_info))
28try:
29for case_validate in case_data['validate']:
30logger.info('断言期望相关参数:check:{},comparator:{},expect:{}'.format(case_validate['check'],
31case_validate['comparator'],
32case_validate['expect']))
33comparatorsTest.comparators_Assert(api_response, case_validate['check'],
34case_validate['comparator'], case_validate['expect'])
35logger.info('测试用例断言成功')
36except Exception as e:
37logger.exception('测试用例断言失败')
38except Exception as e:
39logger.exception('测试用例请求失败,原因:{}'.format(e))
(2)主运行
运用Pytest和Allure的特性,命令行运行测试用例文件夹,并生成对应的allure测试报告。
1 if __name__ == "__main__":
2pytest.main(['-s', '-v', 'test_case/testRequest/', '-q', '--alluredir', 'reports'])
4、Allure2测试报告 当我们运行主函数时,并生成对应的测试用例报告时,我们可以看到在该文件夹中会生成对应的json文件的测试报告。将json文件的测试报告转换成html形式的。命令如下
reports是json格式测试报告存放的目录位置,allure_reports是html测试报告文件生成的目录位置。allure命令如下。
1 allure generate reports -o allure_result/
项目根目录下的allure_reports文件,存放的是allure生成的测试报告。可看出文件下有一个HTML文件,可通过Python的编辑器Pycharm来打开该HTML文件(测试报告),
或可通过allure命令来打开该HTML,展示HTML测试报告。如下所示。
测试报告文件,HTML测试报告如下。
文章图片
allure命令打开HTML测试报告。命令如下所示
1 allure open allure_result/
如下图所示。
文章图片
打开生成的HTML测试报告如下图所示。
文章图片
五、Jenkins集成 Allure+Jenkins的分享,我之前在Pytest+Allure+Jenkins的博客中已经分享过了。这块可以出门左转看看。前期的准备就不在这里重复说明了。我们就直接来上手创建Item进行相关配置。
General中GitHub项目地址的配置,将自己项目的Git复制至项目URL处。如下图所示。
文章图片
源码管理设置。勾选Git,填写相应的项目Git地址,Git项目权限所有者,以及对应的拉取代码的分支。如下图所示。
文章图片
配置构建命令。选择“执行windows批处理命令”,用python运行主函数运行脚本,命令如下图所示
文章图片
当我们在Jenkins里面成功安装Allure插件后,直接可以在构建后操作中配置Allure的相关配置。在Pytest+Allure+Jenkins中已经说明过的。
Results应与项目运行时设置的Allure生成的Json格式报告的路径一致,Report path为Allure html报告结果生成文件存放的路径。
文章图片
排除万难之后,我们就可以用Jenkins来运行项目了。如下图所示。
文章图片
测试报告详情页,如下图所示。
文章图片
文章图片
推荐阅读
- 自动化测试|Python接口自动化测试框架(Pytest+Allure+jsonpath+xlrd+excel、支持Restful接口规范)
- python|接口自动化测试实战之pytest框架+allure讲解
- OAK使用教程|如何将OAK相机当做网络摄像头使用()
- OAK应用案例|【开源】使用PhenoCV-WeedCam进行更智能、更精确的杂草管理
- OAK常见报错|报错ImportError: numpy.core.multiarray failed to import
- js|逆向日记之发票查验平台网站js逆向分析及逆向算法
- python|记一次js逆向解析学习-02
- python|python群发邮件
- 面试|实用 - Java后端面试经历(经验分享)适用于2~3年