51Testing软件测试论坛

 找回密码
 (注-册)加入51Testing

QQ登录

只需一步,快速开始

微信登录,快人一步

手机号码,快捷登录

查看: 995|回复: 2
打印 上一主题 下一主题

[转贴] Python+Pytest+Allure+Git+Jenkins接口自动化框架

[复制链接]
  • TA的每日心情
    无聊
    2022-8-5 09:01
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]测试小兵

    跳转到指定楼层
    1#
    发表于 2022-8-4 16:47:23 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
    本帖最后由 阿蛮的开心姐 于 2022-8-4 16:56 编辑

    一、接口基础
    接口测试是对系统和组件之间的接口进行测试,主要是效验数据的交换,传递和控制管理过程,以及相互逻辑依赖关系。其中接口协议分为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.1、log日志
    项目中的log日志是logbook进行日志记录的,方便测试开发调试时进行排错纠正或修复优化。日志可选择是否打印在屏幕上即运行时是否在终端输出打印。日志格式输出可调整。
    handle_log.py部分源码
    1. def log_type(record, handler):
    2. 2     log = "[{date}] [{level}] [{filename}] [{func_name}] [{lineno}] {msg}".format(
    3. 3         date=record.time,  # 日志时间
    4. 4         level=record.level_name,  # 日志等级
    5. 5         filename=os.path.split(record.filename)[-1],  # 文件名
    6. 6         func_name=record.func_name,  # 函数名
    7. 7         lineno=record.lineno,  # 行号
    8. 8         msg=record.message  # 日志内容
    9. 9     )
    10. 10     return log
    11. 11 # 日志存放路径
    12. 12 LOG_DIR = BasePath + '/log'
    13. 13 print(LOG_DIR)
    14. 14 if not os.path.exists(LOG_DIR):
    15. 15     os.makedirs(LOG_DIR)
    16. 16 # 日志打印到屏幕
    17. 17 log_std = ColorizedStderrHandler(bubble=True)
    18. 18 log_std.formatter = log_type
    19. 19 # 日志打印到文件
    20. 20 log_file = TimedRotatingFileHandler(
    21. 21     os.path.join(LOG_DIR, '%s.log' % 'log'), date_format='%Y-%m-%d', bubble=True, encoding='utf-8')
    22. 22 log_file.formatter = log_type
    23. 23
    24. 24 # 脚本日志
    25. 25 run_log = Logger("global_log")
    26. 26 def init_logger():
    27. 27     logbook.set_datetime_format("local")
    28. 28     run_log.handlers = []
    29. 29     run_log.handlers.append(log_file)
    30. 30     run_log.handlers.append(log_std)
    31. 31     return ""
    复制代码
    打印在终端的日志,如下图所示:
    同时运行项目后,会在项目文件log中自动生成一个以当天日期命名的log文件。点击log日志文件可查看日志详情即项目运行时所记录的日志或报错日志。如下图所示:
    1.2、配置文件
    项目中涉及到一些配置文件如username、password或环境变量时,我们可通过配置文件来获取配置值。通过配置文件中key与value的定义来确定获取配置文件的值。
    handle_init.py部分源码
    1. class HandleInit:
    2. 2     # 读取配置文件
    3. 3     def load_ini(self):
    4. 4         file_path = BasePath + "/config/config.ini"
    5. 5         cf = configparser.ConfigParser()
    6. 6         cf.read(file_path, encoding='UTF-8')
    7. 7         return cf
    8. 8
    9. 9     # 获取ini里面对应key的value
    10. 10     def get_value(self, key, node=None):
    11. 11         if node == None:
    12. 12             node = 'Test'
    13. 13         cf = self.load_ini()
    14. 14         try:
    15. 15             data = cf.get(node, key)
    16. 16             logger.info('获取配置文件的值,node:{},key:{}, data:{}'.format(node, key, data))
    17. 17         except Exception:
    18. 18             logger.exception('没有获取到对应的值,node:{},key:{}'.format(node, key))
    19. 19             data = None
    20. 20         return data
    复制代码
    获取配置文件中的值日志如下图所示:
    1.3、Api接口请求
    获取相关测试用例及接口用例配置,记录请求相关参数的日志,定义Allure测试报告的步骤。
    handle_apirequest.py部分代码
    1. class ApiRequest:
    2. 2     def api_request(self, base_url, test_case_data, case_data):
    3. 3         get_name = None
    4. 4         get_url = None
    5. 5         get_method = None
    6. 6         get_headers = None
    7. 7         get_cookies = None
    8. 8         get_case_name = None
    9. 9         get_case_params = None
    10. 10         response_data = None
    11. 11         try:
    12. 12             get_name = test_case_data['config']['name']
    13. 13             get_url = base_url + test_case_data['config']['url']
    14. 14             get_method = test_case_data['config']['method']
    15. 15             get_headers = test_case_data['config']['headers']
    16. 16             get_cookies = test_case_data['config']['cookies']
    17. 17         except Exception as e:
    18. 18             logger.exception('获取用例基本信息失败,{}'.format(e))
    19. 19         try:
    20. 20             get_case_name = case_data['name']
    21. 21             get_case_params = case_data['params']
    22. 22         except Exception as e:
    23. 23             logger.exception('获取测试用例信息失败,{}'.format(e))
    24. 24         with allure.step("请求接口:%s,请求地址:%s,请求方法:%s,请求头:%s,请求Cookies:%s" % (
    25. 25                 get_name, get_url, get_method, get_headers, get_cookies)):
    26. 26             allure.attach("接口用例描述:", "{0}".format(get_case_name))
    27. 27             allure.attach("接口用例请求参数:", "{0}".format(get_case_params))
    28. 28         logger.info(
    29. 29             '请求接口名:%r,请求地址:%r,请求方法:%r,请求头:%r,请求Cookies:%r' % (get_name, get_url, get_method, get_headers, get_cookies))
    30. 30         logger.info('请求接口名:%r,请求接口用例名:%r,接口用例请求参数:%r' % (get_name, get_case_name, get_case_params))
    31. 31         try:
    32. 32             response_data = baseRequest.run_main(get_method, get_url, get_case_params, get_headers)
    33. 33         except Exception as e:
    34. 34             logger.exception('用例请求返回失败,{}'.format(e))
    35. 35         logger.info('请求接口名:%r,请求接口用例名:%r,返回参数:%r' % (get_name, get_case_name, response_data.json()))
    36. 36         return response_data
    复制代码
    1.4、Excel数据处理1.4.1、Excel测试用例

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



    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
    收藏收藏1
    回复

    使用道具 举报

  • TA的每日心情
    无聊
    2022-8-5 09:01
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]测试小兵

    2#
     楼主| 发表于 2022-8-4 16:51:24 | 只看该作者
    1. class OperationExcel:
    2. 2     def __init__(self, file_name=None, sheet_id=None):
    3. 3         if file_name:
    4. 4             self.file_name = file_name
    5. 5             self.sheet_id = sheet_id
    6. 6         else:
    7. 7             self.file_name = ''
    8. 8             self.sheet_id = 0
    9. 9         self.data = self.get_data()
    10. 10
    11. 11     # 获取sheets的内容
    12. 12     def get_data(self):
    13. 13         data = xlrd.open_workbook(self.file_name)
    14. 14         tables = data.sheets()[self.sheet_id]
    15. 15         return tables
    16. 16
    17. 17     # 获取单元格的行数
    18. 18     def get_lines(self):
    19. 19         tables = self.data
    20. 20         return tables.nrows
    21. 21
    22. 22     # 获取某一个单元格的内容
    23. 23     def get_cell_value(self, row, col):
    24. 24         return self.data.cell_value(row, col)
    复制代码
    1.5、Json数据处理1.5.1、Json测试用例
    1. {
    2. 2     "config":{
    3. 3         "name":"post接口名",
    4. 4         "url":"/langdetect",
    5. 5         "method":"POST",
    6. 6         "headers":{
    7. 7             "Content-Type":"application/json"
    8. 8         },
    9. 9         "cookies":{
    10. 10
    11. 11         }
    12. 12     },
    13. 13     "testcase":[
    14. 14         {
    15. 15             "name":"测试用例1",
    16. 16             "params":{
    17. 17                 "query":"测试"
    18. 18             },
    19. 19             "validate":[
    20. 20                 {
    21. 21                     "check":"status_code",
    22. 22                     "comparator":"eq",
    23. 23                     "expect":"200"
    24. 24                 }
    25. 25             ]
    26. 26         },
    27. 27         {
    28. 28             "name":"测试用例2",
    29. 29             "params":{
    30. 30                 "query":"python"
    31. 31             },
    32. 32             "validate":[
    33. 33                 {
    34. 34                     "check":"msg",
    35. 35                     "comparator":"eq",
    36. 36                     "expect":"success"
    37. 37                 }
    38. 38             ]
    39. 39         }
    40. 40     ]
    41. 41 }
    复制代码
    1.5.2、Json用例处理
    获取Json文件中里具体字段的值。
    handle.json.py部分源码
    1. 1 class HandleJson:
    2. 2     # 读取json文件
    3. 3     def load_json(self, file_name):
    4. 4         if file_name == None:
    5. 5             file_path = ""
    6. 6         else:
    7. 7             file_path = file_name
    8. 8         try:
    9. 9             with open(file_path, encoding='UTF-8') as f:
    10. 10                 data = json.load(f)
    11. 11             return data
    12. 12         except Exception:
    13. 13             print("未找到json文件")
    14. 14             return {}
    15. 15
    16. 16     # 读取json文件里具体的字段值
    17. 17     def getJson_value(self, key, file_name):
    18. 18         if file_name == None:
    19. 19             return ""
    20. 20         jsonData = self.load_json(file_name)
    21. 21         if key == None:
    22. 22             getJsonValue = ""
    23. 23         else:
    24. 24             getJsonValue = jsonData.get(key)
    25. 25         return getJsonValue
    复制代码
    2、基类封装2.1、请求基类封装
    接口支持Get、Post请求,调用requests请求来实现接口的调用与返回。接口参数包括,接口地址、接口请求参数、cookie参数、header参数。
    1. 1 class BaseRequest:
    2. 2
    3. 3     def send_get(self, url, data, header=None, cookie=None):
    4. 4         """
    5. 5         Requests发送Get请求
    6. 6         :param url:请求地址
    7. 7         :param data:Get请求参数
    8. 8         :param cookie:cookie参数
    9. 9         :param header:header参数
    10. 10         """
    11. 11         response = requests.get(url=url, params=data, cookies=cookie, headers=header)
    12. 12         return response
    13. 13
    14. 14     def send_post(self, url, data, header=None, cookie=None):
    15. 15         """
    16. 16         Requests发送Post请求
    17. 17         :param url:请求地址
    18. 18         :param data:Post请求参数
    19. 19         :param data:Post请求参数
    20. 20         :param cookie:cookie参数
    21. 21         :param header:header参数
    22. 22         """
    23. 23         response = requests.post(url=url, json=data, cookies=cookie, headers=header)
    24. 24         return response
    25. 25
    26. 26         # 主函数调用
    27. 27
    28. 28     def run_main(self, method, url, data, header, cookie=None):
    29. 29         try:
    30. 30             result = ''
    31. 31             if method.upper() == 'GET':
    32. 32                 result = self.send_get(url, data, header, cookie)
    33. 33             elif method.upper() == 'POST':
    34. 34                 result = self.send_post(url, data, header, cookie)
    35. 35             return result
    36. 36         except Exception as e:
    37. 37             logger.exception('请求主函数调用失败:{}'.format(e))
    复制代码
    3、接口测试用例编写3.1、接口测试用例
    引用Pytest来进行接口的单元测试,通过JSON中多个测试用例来做为参数化数据驱动。结合Allure制定相应接口的测试报告。在接口返回断言之前,我们先进行该接口的契约测试,
    我们采用的是Pactverity的全量契约校验测试。当契约测试通过时,我们再进行返回参数的相关校验测试。
    test_getRequestJson.py部分源码
    1. @allure.feature('测试GET请求模块')
    2. 2 class TestRequestOne():
    3. 3     @allure.title('测试标题')
    4. 4     @allure.testcase('测试地址:https://www.imooc.com')
    5. 5     @pytest.mark.parametrize('case_data', testCaseData['testcase'])
    6. 6     def test_requestOne(self, case_data):
    7. 7         try:
    8. 8             api_response = apiRequest.api_request(baseurl, testCaseData, case_data)
    9. 9             api_response_data = api_response.json()
    10. 10             # pactverity——全量契约校验
    11. 11             config_contract_format = Like({
    12. 12                 "msg": "成功",
    13. 13                 "result": 0,
    14. 14                 "data": EachLike({
    15. 15                     "word": Like("testng")
    16. 16                 })
    17. 17             })
    18. 18             mPactVerify = PactVerify(config_contract_format)
    19. 19             try:
    20. 20                 mPactVerify.verify(api_response_data)
    21. 21                 logger.info(
    22. 22                     'verify_result:{},verify_info:{}'.format(mPactVerify.verify_result, mPactVerify.verify_info))
    23. 23                 assert mPactVerify.verify_result == True
    24. 24             except Exception:
    25. 25                 err_msg = '契约校验错误'
    26. 26                 logger.exception('测试用例契约校验失败,verify_result:{},verify_info:{}'.format(mPactVerify.verify_result,
    27. 27                                                                                      mPactVerify.verify_info))
    28. 28             try:
    29. 29                 for case_validate in case_data['validate']:
    30. 30                     logger.info('断言期望相关参数:check:{},comparator:{},expect:{}'.format(case_validate['check'],
    31. 31                                                                                    case_validate['comparator'],
    32. 32                                                                                    case_validate['expect']))
    33. 33                     comparatorsTest.comparators_Assert(api_response, case_validate['check'],
    34. 34                                                        case_validate['comparator'], case_validate['expect'])
    35. 35                     logger.info('测试用例断言成功')
    36. 36             except Exception as e:
    37. 37                 logger.exception('测试用例断言失败')
    38. 38         except Exception as e:
    39. 39             logger.exception('测试用例请求失败,原因:{}'.format(e))
    复制代码
    3.2、主运行
    运用Pytest和Allure的特性,命令行运行测试用例文件夹,并生成对应的allure测试报告。
    1. if __name__ == "__main__":
    2. 2     pytest.main(['-s', '-v', 'test_case/testRequest/', '-q', '--alluredir', 'reports'])
    复制代码
    4、Allure2测试报告
    当我们运行主函数时,并生成对应的测试用例报告时,我们可以看到在该文件夹中会生成对应的json文件的测试报告。将json文件的测试报告转换成html形式的。命令如下
    reports是json格式测试报告存放的目录位置,allure_reports是html测试报告文件生成的目录位置。allure命令如下。
    1. 1 allure generate reports -o allure_result/
    复制代码
    项目根目录下的allure_reports文件,存放的是allure生成的测试报告。可看出文件下有一个HTML文件,可通过Python的编辑器Pycharm来打开该HTML文件(测试报告),
    或可通过allure命令来打开该HTML,展示HTML测试报告。如下所示。
    测试报告文件,HTML测试报告如下。
    allure命令打开HTML测试报告。命令如下所示。
    1. 1 allure open allure_result/
    复制代码
    如下图所示


    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    回复 支持 反对

    使用道具 举报

  • TA的每日心情
    无聊
    2022-8-5 09:01
  • 签到天数: 2 天

    连续签到: 2 天

    [LV.1]测试小兵

    3#
     楼主| 发表于 2022-8-4 16:55:47 | 只看该作者
    打开生成的HTML测试报告如下图所示

    5、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来运行项目了。如下图所示。
    测试报告详情页,如下图所示
    六、后期优化
    1、接口测试用例之间的数据依赖
    2、测试报告邮件的发送
    。。。。。。
    七、感想
    该框架是在涉及python的知识点比较多,将接口测试与契约测试结合起来。该框架是在工作之余学习多篇文章,实战上手逐步入门开始的,适合新手入门接口自动化实战练习,仅供参考学习。框架中有不少可优化点与不足点,希望大家多多提建议或想法。

    本帖子中包含更多资源

    您需要 登录 才可以下载或查看,没有帐号?(注-册)加入51Testing

    x
    回复 支持 反对

    使用道具 举报

    本版积分规则

    关闭

    站长推荐上一条 /1 下一条

    小黑屋|手机版|Archiver|51Testing软件测试网 ( 沪ICP备05003035号 关于我们

    GMT+8, 2024-11-18 22:29 , Processed in 0.064917 second(s), 23 queries .

    Powered by Discuz! X3.2

    © 2001-2024 Comsenz Inc.

    快速回复 返回顶部 返回列表