接口自动化测试框架搭建:基于Python+Requests+Pytest的实战教程

接口自动化测试框架搭建:基于Python+Requests+Pytest的实战教程 在软件测试领域接口自动化测试是保障系统稳定性、提升测试效率的关键手段。随着敏捷开发和DevOps理念的普及自动化测试的重要性愈发凸显。Python凭借其简洁的语法、丰富的库生态成为接口自动化测试的首选语言Requests库让HTTP请求的发送变得简单高效Pytest则以其灵活的用例管理、强大的断言机制和丰富的插件生态成为测试框架的佼佼者。本文将从专业角度详细介绍如何基于PythonRequestsPytest搭建一套高效、可扩展的接口自动化测试框架。一、框架搭建前的准备工作1.1 环境配置工欲善其事必先利其器。搭建框架前需要确保开发环境的正确配置Python环境推荐使用Python 3.8及以上版本该版本在Windows、MacOS和Linux系统上均有良好的兼容性且能较好地支持后续所需的第三方库。可以通过Python官方网站下载安装包或使用Pyenv、Miniconda等工具进行版本管理避免不同项目之间的环境冲突。虚拟环境创建为了隔离不同项目的依赖建议创建虚拟环境。在项目根目录下执行以下命令python -m venv venv # Linux/Mac系统激活虚拟环境 source venv/bin/activate # Windows系统激活虚拟环境 venv\Scripts\activate.bat核心依赖安装激活虚拟环境后安装框架所需的核心库。执行以下命令pip install pytest7.4.0 requests2.31.0 allure-pytest2.13.2 pytest-html4.1.1pytest测试框架核心用于用例管理、执行和断言。requests发送HTTP请求的库支持GET、POST、PUT、DELETE等多种请求方式。allure-pytest生成Allure测试报告的插件提供美观、详细的可视化报告。pytest-html生成HTML格式的测试报告方便快速查看测试结果。1.2 项目目录结构设计合理的目录结构是框架可维护性和扩展性的基础。经过多个项目的实践验证以下目录结构具有较高的实用性api_auto_test/ ├── config/ # 配置文件目录 │ ├── __init__.py │ ├── global_config.py # 全局配置变量如环境地址、超时时间等 │ └── pytest.ini # Pytest配置文件 ├── testcases/ # 测试用例目录 │ ├── __init__.py │ ├── test_user_api.py # 用户模块接口测试用例 │ └── test_order_api.py # 订单模块接口测试用例 ├── utils/ # 工具类目录 │ ├── __init__.py │ ├── request_util.py # 请求工具类封装HTTP请求方法 │ └── assert_util.py # 断言工具类封装自定义断言方法 ├── resources/ # 测试数据目录 │ ├── __init__.py │ ├── user_data.yaml # 用户模块测试数据 │ └── order_data.json # 订单模块测试数据 ├── reports/ # 测试报告目录 │ ├── html/ # HTML报告存放路径 │ └── allure/ # Allure报告原始数据存放路径 ├── logs/ # 日志文件目录 ├── requirements.txt # 项目依赖清单 └── run.py # 测试执行入口config目录存放全局配置信息通过global_config.py统一管理不同环境的地址、接口超时时间等参数方便环境切换。pytest.ini用于配置Pytest的运行参数如测试用例发现规则、报告生成路径等。testcases目录按照业务模块划分测试用例每个模块对应一个测试文件便于维护和扩展。utils目录封装通用的工具方法如请求发送、断言验证等提高代码复用率。resources目录存放测试数据支持YAML、JSON等格式实现测试数据与代码的分离便于非技术人员维护测试数据。reports目录存放测试报告分为HTML和Allure两种格式满足不同场景的需求。logs目录记录测试执行过程中的日志信息便于问题排查。requirements.txt记录项目依赖的库及其版本方便团队成员快速搭建一致的开发环境。run.py作为测试执行的入口通过代码方式配置Pytest的运行参数实现一键执行测试。二、核心模块封装2.1 请求工具类封装Requests库虽然使用简单但在实际项目中直接使用其原生方法会导致代码冗余且不利于统一管理请求头、超时时间、异常处理等。因此需要对Requests进行二次封装实现请求的标准化和统一化。在utils/request_util.py中封装请求工具类import requests from requests.adapters import HTTPAdapter from urllib3.util.retry import Retry from config.global_config import GlobalConfig class RequestUtil: def __init__(self): self.session requests.Session() # 配置重试机制 retry Retry( totalGlobalConfig.RETRY_TIMES, backoff_factorGlobalConfig.BACKOFF_FACTOR, status_forcelist[500, 502, 503, 504] ) adapter HTTPAdapter(max_retriesretry) self.session.mount(http://, adapter) self.session.mount(https://, adapter) # 设置默认超时时间 self.timeout GlobalConfig.TIMEOUT def send_request(self, method, url, **kwargs): 发送HTTP请求 :param method: 请求方法如GET、POST、PUT、DELETE等 :param url: 请求地址 :param kwargs: 其他请求参数如headers、params、json、data等 :return: 响应对象 try: response self.session.request( methodmethod.upper(), urlurl, timeoutself.timeout, **kwargs ) response.raise_for_status() # 抛出HTTP错误异常 return response except requests.exceptions.RequestException as e: print(f请求发送失败: {str(e)}) raise上述代码中通过Session对象建立持久连接提高请求效率配置重试机制当遇到500、502等服务器错误时自动重试指定次数设置默认超时时间避免请求长时间阻塞捕获并处理请求过程中的异常确保测试用例的稳定性。2.2 断言工具类封装Pytest支持使用Python原生的assert语句进行断言但在实际项目中原生断言的错误信息不够直观不利于问题定位。因此需要封装自定义的断言方法提供更详细的错误提示。在utils/assert_util.py中封装断言工具类class AssertUtil: staticmethod def assert_equal(actual, expected, msgNone): 断言两个值相等 :param actual: 实际结果 :param expected: 预期结果 :param msg: 断言失败时的提示信息 try: assert actual expected, msg or f实际结果: {actual} 与预期结果: {expected} 不相等 except AssertionError as e: print(f断言失败: {str(e)}) raise staticmethod def assert_in(actual, expected, msgNone): 断言预期结果包含在实际结果中 :param actual: 实际结果 :param expected: 预期包含的内容 :param msg: 断言失败时的提示信息 try: assert expected in actual, msg or f预期内容: {expected} 未在实际结果: {actual} 中找到 except AssertionError as e: print(f断言失败: {str(e)}) raise staticmethod def assert_status_code(response, expected_code): 断言响应状态码 :param response: 响应对象 :param expected_code: 预期状态码 try: assert response.status_code expected_code, \ f响应状态码错误实际状态码: {response.status_code}预期状态码: {expected_code} except AssertionError as e: print(f断言失败: {str(e)}) raise通过封装这些断言方法在测试用例中调用时能够得到更清晰的错误提示提高问题排查效率。2.3 配置文件管理在config/global_config.py中定义全局配置变量实现不同环境的统一管理class GlobalConfig: # 环境配置 ENV test # 测试环境test、pre、prod BASE_URLS { test: https://test.example.com/api, pre: https://pre.example.com/api, prod: https://example.com/api } BASE_URL BASE_URLS[ENV] # 请求配置 TIMEOUT 10 # 请求超时时间单位秒 RETRY_TIMES 3 # 请求重试次数 BACKOFF_FACTOR 1 # 重试间隔时间系数 # 日志配置 LOG_LEVEL INFO LOG_FORMAT %(asctime)s - %(name)s - %(levelname)s - %(message)s通过修改ENV变量即可快速切换测试环境无需在多个测试文件中逐一修改接口地址大大提高了环境切换的效率。三、测试用例编写3.1 测试用例设计原则编写测试用例时应遵循以下原则单一职责原则每个测试用例只关注一个功能点确保用例的独立性和可维护性。覆盖全面原则覆盖正常场景、异常场景和边界场景确保接口的稳定性和健壮性。数据驱动原则将测试数据与测试代码分离通过YAML、JSON等文件管理测试数据提高用例的复用性和灵活性。3.2 测试用例编写示例以用户模块的登录接口为例在testcases/test_user_api.py中编写测试用例import pytest from utils.request_util import RequestUtil from utils.assert_util import AssertUtil from config.global_config import GlobalConfig import yaml # 加载测试数据 with open(resources/user_data.yaml, r, encodingutf-8) as f: user_data yaml.safe_load(f) class TestUserAPI: def setup_class(self): 测试类初始化方法在所有测试方法执行前执行一次 self.request_util RequestUtil() self.assert_util AssertUtil() self.login_url f{GlobalConfig.BASE_URL}/user/login pytest.mark.parametrize(case, user_data[login_success_cases]) def test_login_success(self, case): 登录接口正常场景测试 # 发送请求 response self.request_util.send_request( methodPOST, urlself.login_url, jsoncase[request_data] ) # 断言响应状态码 self.assert_util.assert_status_code(response, case[expected_code]) # 断言响应内容 response_json response.json() self.assert_util.assert_in(token, response_json, 登录成功未返回token) self.assert_util.assert_equal(response_json[code], case[expected_code], 响应码与预期不符) pytest.mark.parametrize(case, user_data[login_fail_cases]) def test_login_fail(self, case): 登录接口异常场景测试 # 发送请求 response self.request_util.send_request( methodPOST, urlself.login_url, jsoncase[request_data] ) # 断言响应状态码 self.assert_util.assert_status_code(response, case[expected_code]) # 断言响应内容 response_json response.json() self.assert_util.assert_equal(response_json[code], case[expected_code], 响应码与预期不符) self.assert_util.assert_equal(response_json[msg], case[expected_msg], 响应提示信息与预期不符) 测试数据文件resources/user_data.yaml内容如下 login_success_cases: - case_name: 正确用户名和密码登录 request_data: username: test_user password: test123 expected_code: 200 expected_msg: 登录成功 login_fail_cases: - case_name: 用户名不存在 request_data: username: invalid_user password: test123 expected_code: 400 expected_msg: 用户名不存在 - case_name: 密码错误 request_data: username: test_user password: wrong_password expected_code: 400 expected_msg: 密码错误通过pytest.mark.parametrize装饰器实现数据驱动测试将测试数据与测试代码分离提高了用例的复用性和灵活性。每个测试用例只关注一个场景确保了用例的独立性和可维护性。四、测试执行与报告生成4.1 测试执行在项目根目录下创建run.py文件作为测试执行的入口import pytest import os if __name__ __main__: # 配置测试报告路径 html_report_path os.path.join(reports, html, report.html) allure_report_path os.path.join(reports, allure) # 构建Pytest命令行参数 args [ testcases/, -v, # 显示详细的测试结果 --html html_report_path, # 生成HTML报告 --alluredir allure_report_path, # 生成Allure报告原始数据 --clean-alluredir # 清空之前的Allure报告数据 ] # 执行测试 pytest.main(args)运行run.py文件即可执行所有测试用例。执行过程中Pytest会自动发现testcases目录下的测试用例并按照配置生成测试报告。4.2 测试报告查看HTML报告测试执行完成后打开reports/html/report.html文件即可查看HTML格式的测试报告。报告中包含了测试用例的执行结果、执行时间、失败用例的详细信息等便于快速查看测试结果。Allure报告生成Allure报告需要先安装Allure命令行工具安装完成后在项目根目录下执行以下命令allure serve reports/allure命令执行后会启动一个本地服务器并在浏览器中打开Allure报告。Allure报告提供了更丰富的可视化信息如测试用例的执行趋势、失败用例的堆栈信息、测试覆盖率等便于深入分析测试结果。五、框架扩展与优化5.1 日志功能集成在测试执行过程中日志信息对于问题排查至关重要。可以使用Python的logging模块封装日志工具类实现日志的记录和管理。在utils/log_util.py中封装日志工具类import logging from config.global_config import GlobalConfig import os class LogUtil: def __init__(self, logger_name): self.logger logging.getLogger(logger_name) self.logger.setLevel(GlobalConfig.LOG_LEVEL) # 避免重复添加处理器 if not self.logger.handlers: # 创建日志文件目录 if not os.path.exists(logs): os.makedirs(logs) # 创建文件处理器 file_handler logging.FileHandler( os.path.join(logs, test.log), encodingutf-8 ) file_handler.setLevel(GlobalConfig.LOG_LEVEL) # 创建控制台处理器 console_handler logging.StreamHandler() console_handler.setLevel(GlobalConfig.LOG_LEVEL) # 创建日志格式器 formatter logging.Formatter(GlobalConfig.LOG_FORMAT) file_handler.setFormatter(formatter) console_handler.setFormatter(formatter) # 添加处理器到日志器 self.logger.addHandler(file_handler) self.logger.addHandler(console_handler) def get_logger(self): return self.logger在请求工具类和测试用例中集成日志功能记录请求的发送、响应的返回以及断言的结果等信息便于问题排查。5.2 持续集成集成将接口自动化测试框架与Jenkins、GitLab CI等持续集成工具集成实现代码提交后自动触发测试提高测试效率。以Jenkins为例配置步骤如下在Jenkins中创建一个新的任务选择“自由风格项目”。在“源码管理”中配置Git仓库地址拉取测试代码。在“构建环境”中配置Python虚拟环境激活虚拟环境并安装依赖。在“构建”步骤中执行python run.py命令启动测试。在“构建后操作”中配置Allure报告的展示便于查看测试结果。通过持续集成集成实现了测试的自动化执行确保了代码的质量和稳定性。六、总结基于PythonRequestsPytest搭建的接口自动化测试框架具有简洁高效、可扩展性强、易于维护等优点。通过合理的目录结构设计、核心模块的封装、测试用例的规范编写以及测试报告的生成能够有效提升接口自动化测试的效率和质量。同时通过框架的扩展与优化如日志功能集成、持续集成集成等进一步增强了框架的实用性和稳定性。在实际项目中应根据项目的具体需求对框架进行适当的调整和优化以满足项目的测试需求。