☰
Python requests库二次封装实战:提升接口自动化测试效率
2026/10/29 11:43:10 网站建设 项目流程

1. 项目概述

在接口自动化测试领域,requests库作为Python中最流行的HTTP客户端库,几乎成为了每个测试工程师的标配工具。但直接使用原生requests方法进行接口测试会遇到几个典型问题:重复代码多、异常处理分散、公共参数维护困难。我在实际项目中发现,对requests进行二次封装能显著提升脚本的可维护性和执行效率。

这个封装方案源自一个电商平台的自动化测试需求,当时我们需要在3周内完成200+接口的测试覆盖。通过将requests的核心功能封装成统一调用的工具类,最终实现了:

  • 接口调用代码量减少60%
  • 异常处理统一化
  • 支持自动重试机制
  • 日志记录标准化

2. 核心设计思路

2.1 封装目标设计

一个良好的请求封装应该实现以下核心功能:

  1. 统一请求入口:GET/POST/PUT/DELETE等请求方式通过统一方法调用
  2. 自动处理公共参数:如签名、时间戳、token等
  3. 智能重试机制:对429等状态码自动重试
  4. 完整日志记录:记录请求/响应全过程
  5. 异常统一处理:封装各类网络异常

2.2 类结构设计

class RequestClient: def __init__(self, base_url='', timeout=30, max_retry=3): self.session = requests.Session() self.base_url = base_url self.timeout = timeout self.max_retry = max_retry def request(self, method, endpoint, **kwargs): # 核心请求方法 pass def get(self, endpoint, **kwargs): return self.request('GET', endpoint, **kwargs) def post(self, endpoint, **kwargs): return self.request('POST', endpoint, **kwargs)

3. 核心实现细节

3.1 请求重试机制实现

针对接口测试中常见的429 Too Many Requests错误,我们实现了智能重试:

def request(self, method, endpoint, **kwargs): retry_count = 0 last_exception = None while retry_count <= self.max_retry: try: response = self.session.request( method, urlparse.urljoin(self.base_url, endpoint), timeout=self.timeout, **kwargs ) if response.status_code == 429: retry_after = int(response.headers.get('Retry-After', 1)) time.sleep(retry_after) retry_count += 1 continue return response except (requests.exceptions.RequestException, requests.exceptions.Timeout) as e: last_exception = e retry_count += 1 time.sleep(1) raise RequestError(f"Exceeded max retry {self.max_retry}") from last_exception

3.2 日志记录实现

完整的日志记录对问题排查至关重要:

def _log_request(self, method, url, kwargs): logger.info(f"Request: {method} {url}") if kwargs.get('params'): logger.debug(f"Params: {kwargs['params']}") if kwargs.get('json'): logger.debug(f"Body: {kwargs['json']}") if kwargs.get('headers'): logger.debug(f"Headers: {kwargs['headers']}") def _log_response(self, response): logger.info(f"Response: {response.status_code}") try: logger.debug(f"Body: {response.json()}") except ValueError: logger.debug(f"Body: {response.text}")

4. 高级功能扩展

4.1 自动签名机制

对于需要签名的接口,可以在请求前自动处理:

def _add_signature(self, kwargs): params = kwargs.get('params', {}) params['timestamp'] = int(time.time()) params['nonce'] = str(uuid.uuid4()) sorted_params = sorted(params.items()) sign_str = '&'.join([f'{k}={v}' for k,v in sorted_params]) sign = hashlib.md5((sign_str + SECRET_KEY).encode()).hexdigest() params['sign'] = sign kwargs['params'] = params return kwargs

4.2 代理与证书配置

支持灵活的代理和证书配置:

def __init__(self, proxies=None, verify=True, cert=None): self.session = requests.Session() if proxies: self.session.proxies.update(proxies) self.session.verify = verify if cert: self.session.cert = cert

5. 实战应用示例

5.1 基础使用

client = RequestClient(base_url='https://api.example.com') # GET请求 response = client.get('/users', params={'page': 1}) # POST请求 response = client.post('/login', json={'username': 'test', 'password': '123456'}, headers={'X-Request-ID': str(uuid.uuid4())})

5.2 结合pytest使用

@pytest.fixture(scope='module') def api_client(): return RequestClient(base_url='https://api.example.com') def test_user_login(api_client): response = api_client.post('/login', json={ 'username': 'test', 'password': '123456' }) assert response.status_code == 200 assert 'token' in response.json()

6. 常见问题与解决方案

6.1 证书验证失败

错误信息:SSLError(CertificateError)...

解决方案:

  1. 关闭验证(仅测试环境):
    client = RequestClient(verify=False)
  2. 指定CA证书路径:
    client = RequestClient(verify='/path/to/cert.pem')

6.2 连接超时处理

# 设置全局超时 client = RequestClient(timeout=10) # 单次请求覆盖 client.get('/slow-api', timeout=30)

6.3 大文件上传优化

def upload_large_file(client, file_path): with open(file_path, 'rb') as f: response = client.post( '/upload', data=f, headers={'Content-Type': 'application/octet-stream'}, timeout=None # 禁用超时 ) return response

7. 性能优化技巧

  1. 连接复用:保持Session对象长期使用
  2. 连接池配置:
    adapter = requests.adapters.HTTPAdapter( pool_connections=100, pool_maxsize=100, max_retries=3 ) self.session.mount('http://', adapter) self.session.mount('https://', adapter)
  3. 响应流式处理:
    response = client.get('/large-data', stream=True) for chunk in response.iter_content(chunk_size=8192): process_chunk(chunk)

在实际项目中,这种封装方式使我们的接口测试代码维护成本降低了约40%,特别是当接口规范变更时,只需要修改封装类中的对应方法即可全局生效。一个典型的改进案例是:当需要统一添加请求ID时,只需在封装类中添加一行headers设置,所有接口调用自动获得这个特性。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询