淘先锋技术网

首页 1 2 3 4 5 6 7

Python+Pytest+Allure+Git+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

三、接口测试框架结构图

1631583-20200814102847764-914505622.png

四、项目功能

Python+Pytest+Allure+Jenkins接口自动化框架,实现Excel或Json维护测试用例,支持数据库操作,利用封装的请求基类调取相应的测试用例接口,获取配置文件中的环境地址与环境变量,

结合Pytest进行单元测试,使用LogBook进行记录日志,并生成allure测试报告,最后进行Jenkins集成项目实现集成部署,并发送测试报告邮件。

五、代码设计与功能说明

1、工具类封装

1.1、log日志

项目中的log日志是logbook进行日志记录的,方便测试开发调试时进行排错纠正或修复优化。日志可选择是否打印在屏幕上即运行时是否在终端输出打印。日志格式输出可调整。

handle_log.py部分源码

1 deflog_type(record, handler):2 log = "[{date}] [{level}] [{filename}] [{func_name}] [{lineno}] {msg}".format(3 date=record.time, #日志时间

4 level=record.level_name, #日志等级

5 filename=os.path.split(record.filename)[-1], #文件名

6 func_name=record.func_name, #函数名

7 lineno=record.lineno, #行号

8 msg=record.message #日志内容

9 )10 returnlog11 #日志存放路径

12 LOG_DIR = BasePath + '/log'

13 print(LOG_DIR)14 if notos.path.exists(LOG_DIR):15 os.makedirs(LOG_DIR)16 #日志打印到屏幕

17 log_std = ColorizedStderrHandler(bubble=True)18 log_std.formatter =log_type19 #日志打印到文件

20 log_file =TimedRotatingFileHandler(21 os.path.join(LOG_DIR, '%s.log' % 'log'), date_format='%Y-%m-%d', bubble=True, encoding='utf-8')22 log_file.formatter =log_type23

24 #脚本日志

25 run_log = Logger("global_log")26 definit_logger():27 logbook.set_datetime_format("local")28 run_log.handlers =[]29 run_log.handlers.append(log_file)30 run_log.handlers.append(log_std)31 return ""

打印在终端的日志,如下图所示。

1631583-20200814104738582-474136552.png

同时运行项目后,会在项目文件log中自动生成一个以当天日期命名的log文件。点击log日志文件可查看日志详情即项目运行时所记录的日志或报错日志。如下图所示。

1631583-20200814104753714-943712222.png

1.2、配置文件

项目中涉及到一些配置文件如username、password或环境变量时,我们可通过配置文件来获取配置值。通过配置文件中key与value的定义来确定获取配置文件的值。

handle_init.py部分源码

1 classHandleInit:2 #读取配置文件

3 defload_ini(self):4 file_path = BasePath + "/config/config.ini"

5 cf =configparser.ConfigParser()6 cf.read(file_path, encoding='UTF-8')7 returncf8

9 #获取ini里面对应key的value

10 def get_value(self, key, node=None):11 if node ==None:12 node = 'Test'

13 cf =self.load_ini()14 try:15 data =cf.get(node, key)16 logger.info('获取配置文件的值,node:{},key:{}, data:{}'.format(node, key, data))17 exceptException:18 logger.exception('没有获取到对应的值,node:{},key:{}'.format(node, key))19 data =None20 return data

获取配置文件中的值日志如下图所示。

1631583-20200814104938662-1947620486.png

1.3、Api接口请求

获取相关测试用例及接口用例配置,记录请求相关参数的日志,定义Allure测试报告的步骤。

handle_apirequest.py部分代码

1 classApiRequest:2 defapi_request(self, base_url, test_case_data, case_data):3 get_name =None4 get_url =None5 get_method =None6 get_headers =None7 get_cookies =None8 get_case_name =None9 get_case_params =None10 response_data =None11 try:12 get_name = test_case_data['config']['name']13 get_url = base_url + test_case_data['config']['url']14 get_method = test_case_data['config']['method']15 get_headers = test_case_data['config']['headers']16 get_cookies = test_case_data['config']['cookies']17 exceptException as e:18 logger.exception('获取用例基本信息失败,{}'.format(e))19 try:20 get_case_name = case_data['name']21 get_case_params = case_data['params']22 exceptException as e:23 logger.exception('获取测试用例信息失败,{}'.format(e))24 with allure.step("请求接口:%s,请求地址:%s,请求方法:%s,请求头:%s,请求Cookies:%s" %(25 get_name, get_url, get_method, get_headers, get_cookies)):26 allure.attach("接口用例描述:", "{0}".format(get_case_name))27 allure.attach("接口用例请求参数:", "{0}".format(get_case_params))28 logger.info(29 '请求接口名:%r,请求地址:%r,请求方法:%r,请求头:%r,请求Cookies:%r' %(get_name, get_url, get_method, get_headers, get_cookies))30 logger.info('请求接口名:%r,请求接口用例名:%r,接口用例请求参数:%r' %(get_name, get_case_name, get_case_params))31 try:32 response_data =baseRequest.run_main(get_method, get_url, get_case_params, get_headers)33 exceptException as e:34 logger.exception('用例请求返回失败,{}'.format(e))35 logger.info('请求接口名:%r,请求接口用例名:%r,返回参数:%r' %(get_name, get_case_name, response_data.json()))36 return response_data

1.4、Excel数据处理

1.4.1、Excel测试用例

1631583-20200814112726163-150559204.png

测试用例中维护在Excel文件中,类中定义如何获取Excel中的相关数据(如获取某个单元格的内容,获取单元格的行数,以及将数据写入Excel中等操作)。

handle_exceldata.py部分源码

1 classOperationExcel:2 def __init__(self, file_name=None, sheet_id=None):3 iffile_name:4 self.file_name =file_name5 self.sheet_id =sheet_id6 else:7 self.file_name = ''

8 self.sheet_id =09 self.data =self.get_data()10

11 #获取sheets的内容

12 defget_data(self):13 data =xlrd.open_workbook(self.file_name)14 tables =data.sheets()[self.sheet_id]15 returntables16

17 #获取单元格的行数

18 defget_lines(self):19 tables =self.data20 returntables.nrows21

22 #获取某一个单元格的内容

23 defget_cell_value(self, row, col):24 return self.data.cell_value(row, col)

1.5、Json数据处理

1.5.1、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 }

1.5.2、Json用例处理

获取Json文件中里具体字段的值。

handle.json.py部分源码

1 classHandleJson:2 #读取json文件

3 defload_json(self, file_name):4 if file_name ==None:5 file_path = ""

6 else:7 file_path =file_name8 try:9 with open(file_path, encoding='UTF-8') as f:10 data =json.load(f)11 returndata12 exceptException:13 print("未找到json文件")14 return{}15

16 #读取json文件里具体的字段值

17 defgetJson_value(self, key, file_name):18 if file_name ==None:19 return ""

20 jsonData =self.load_json(file_name)21 if key ==None:22 getJsonValue = ""

23 else:24 getJsonValue =jsonData.get(key)25 return getJsonValue

2、基类封装

2.1、请求基类封装

接口支持Get、Post请求,调用requests请求来实现接口的调用与返回。接口参数包括,接口地址、接口请求参数、cookie参数、header参数。

1 classBaseRequest:2

3 def send_get(self, url, data, header=None, cookie=None):4 """

5 Requests发送Get请求6 :param url:请求地址7 :param data:Get请求参数8 :param cookie:cookie参数9 :param header:header参数10 """

11 response = requests.get(url=url, params=data, cookies=cookie, headers=header)12 returnresponse13

14 def send_post(self, url, data, header=None, cookie=None):15 """

16 Requests发送Post请求17 :param url:请求地址18 :param data:Post请求参数19 :param data:Post请求参数20 :param cookie:cookie参数21 :param header:header参数22 """

23 response = requests.post(url=url, json=data, cookies=cookie, headers=header)24 returnresponse25

26 #主函数调用

27

28 def run_main(self, method, url, data, header, cookie=None):29 try:30 result = ''

31 if method.upper() == 'GET':32 result =self.send_get(url, data, header, cookie)33 elif method.upper() == 'POST':34 result =self.send_post(url, data, header, cookie)35 returnresult36 exceptException as e:37 logger.exception('请求主函数调用失败:{}'.format(e))

3、接口测试用例编写

3.1、接口测试用例

引用Pytest来进行接口的单元测试,通过JSON中多个测试用例来做为参数化数据驱动。结合Allure制定相应接口的测试报告。在接口返回断言之前,我们先进行该接口的契约测试,

我们采用的是Pactverity的全量契约校验测试。当契约测试通过时,我们再进行返回参数的相关校验测试。

test_getRequestJson.py部分源码

1 @allure.feature('测试GET请求模块')2 classTestRequestOne():3 @allure.title('测试标题')4 @allure.testcase('测试地址:https://www.imooc.com')5 @pytest.mark.parametrize('case_data', testCaseData['testcase'])6 deftest_requestOne(self, case_data):7 try:8 api_response =apiRequest.api_request(baseurl, testCaseData, case_data)9 api_response_data =api_response.json()10 #pactverity——全量契约校验

11 config_contract_format =Like({12 "msg": "成功",13 "result": 0,14 "data": EachLike({15 "word": Like("testng")16 })17 })18 mPactVerify =PactVerify(config_contract_format)19 try:20 mPactVerify.verify(api_response_data)21 logger.info(22 'verify_result:{},verify_info:{}'.format(mPactVerify.verify_result, mPactVerify.verify_info))23 assert mPactVerify.verify_result ==True24 exceptException:25 err_msg = '契约校验错误'

26 logger.exception('测试用例契约校验失败,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,27 mPactVerify.verify_info))28 try:29 for case_validate in case_data['validate']:30 logger.info('断言期望相关参数:check:{},comparator:{},expect:{}'.format(case_validate['check'],31 case_validate['comparator'],32 case_validate['expect']))33 comparatorsTest.comparators_Assert(api_response, case_validate['check'],34 case_validate['comparator'], case_validate['expect'])35 logger.info('测试用例断言成功')36 exceptException as e:37 logger.exception('测试用例断言失败')38 exceptException as e:39 logger.exception('测试用例请求失败,原因:{}'.format(e))

3.2、主运行

运用Pytest和Allure的特性,命令行运行测试用例文件夹,并生成对应的allure测试报告。

1 if __name__ == "__main__":2 pytest.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测试报告如下。

1631583-20200814113732302-745093278.png

allure命令打开HTML测试报告。命令如下所示。

1 allure open allure_result/

如下图所示。

1631583-20200814113814371-389474966.png

打开生成的HTML测试报告如下图所示。

1631583-20200814113835389-1475350781.png

5、Jenkins集成

Allure+Jenkins的分享,我之前在Pytest+Allure+Jenkins的博客中已经分享过了。这块可以出门左转看看。前期的准备就不在这里重复说明了。我们就直接来上手创建Item进行相关配置。

General中GitHub项目地址的配置,将自己项目的Git复制至项目URL处。如下图所示。

1631583-20200814113855932-641916231.png

源码管理设置。勾选Git,填写相应的项目Git地址,Git项目权限所有者,以及对应的拉取代码的分支。如下图所示。

1631583-20200814113915388-1322929712.png

配置构建命令。选择“执行windows批处理命令”,用python运行主函数运行脚本,命令如下图所示。

1631583-20200814113946036-1853173473.png

当我们在Jenkins里面成功安装Allure插件后,直接可以在构建后操作中配置Allure的相关配置。在Pytest+Allure+Jenkins中已经说明过的。

Results应与项目运行时设置的Allure生成的Json格式报告的路径一致,Report path为Allure html报告结果生成文件存放的路径。

1631583-20200814114010460-636003968.png

排除万难之后,我们就可以用Jenkins来运行项目了。如下图所示。

1631583-20200814114025425-1391819685.png

测试报告详情页,如下图所示。

1631583-20200814114046437-438767760.png

六、后期优化

1、接口测试用例之间的数据依赖

2、测试报告邮件的发送

。。。。。。

七、感想

该框架是在涉及python的知识点比较多,将接口测试与契约测试结合起来。该框架是在工作之余学习多篇文章,实战上手逐步入门开始的,适合新手入门接口自动化实战练习,仅供参考学习。框架中有不少可优化点与不足点,希望大家多多提建议或想法。

开源地址:https://github.com/wuwei88/Apiautomation.git