不止于抓包:用Mitmproxy + Python脚本实现iOS/Android App自动化测试数据Mock

不止于抓包:用Mitmproxy + Python脚本实现iOS/Android App自动化测试数据Mock 不止于抓包用Mitmproxy Python脚本实现iOS/Android App自动化测试数据Mock在移动应用开发的生命周期中自动化测试是确保产品质量的关键环节。然而传统的测试方法往往受限于后端服务的稳定性和多样性难以模拟复杂的网络环境和异常数据场景。这正是Mitmproxy结合Python脚本大显身手的领域——它不仅是一个抓包工具更是自动化测试中数据Mock的瑞士军刀。想象一下这样的场景你需要测试App在网络延迟时的表现或者验证它对异常API响应的容错能力。传统方法可能需要修改后端代码或搭建复杂的测试环境而MitmproxyPython的方案则可以在不修改任何生产代码的情况下动态拦截和修改网络请求实现各种测试场景的快速模拟。本文将带你深入这一技术组合的高级应用从原理到实践构建一个完整的Mock服务解决方案。1. Mitmproxy在自动化测试中的核心优势Mitmproxy之所以成为自动化测试的利器源于其独特的架构设计和工作原理。与常见的抓包工具不同Mitmproxy是一个基于Python开发的中间人代理提供了完整的API用于编程式地操控网络流量。三大核心能力使其在测试领域脱颖而出实时流量拦截与修改可以在请求到达服务器前或响应返回客户端前进行动态修改脚本化控制通过Python脚本实现复杂的流量处理逻辑多协议支持不仅支持HTTP/HTTPS还能处理WebSocket等现代协议对比其他方案Mitmproxy的最大优势在于其灵活性。例如传统的Mock服务器需要预先定义所有可能的响应而Mitmproxy可以根据运行时条件动态生成响应。这在需要模拟大量测试用例或复杂业务逻辑时尤其有价值。提示Mitmproxy的透明代理模式特别适合移动端测试因为它不需要修改App代码或配置只需设置设备网络即可生效。2. 环境搭建与基础配置2.1 安装与基本配置在Mac上安装Mitmproxy非常简单推荐使用Homebrewbrew install mitmproxy对于Python脚本支持建议创建一个虚拟环境python -m venv mitm-env source mitm-env/bin/activate pip install mitmproxy2.2 透明代理与正向代理的选择在移动测试场景中我们通常面临两种代理模式选择特性透明代理正向代理设备配置需修改网络设置需在App或系统中配置代理适用场景无法修改代理设置的App可控制代理配置的环境复杂度初始配置复杂配置简单兼容性可能遇到证书问题证书管理更直观对于iOS/Android设备测试透明代理通常是更好的选择因为它不需要修改App本身。以下是配置透明代理的关键步骤# 启用IP转发 sudo sysctl -w net.inet.ip.forwarding1 # 设置端口转发规则 echo rdr pass on en0 inet proto tcp to any port {80,443} - 127.0.0.1 port 8080 | sudo pfctl -ef - # 启动Mitmproxy透明模式 mitmdump --mode transparent -s mock_script.py3. Python脚本开发从基础到高级3.1 基本请求拦截创建一个基础的Mock脚本mock_script.py来拦截和修改请求from mitmproxy import http def request(flow: http.HTTPFlow) - None: # 拦截特定API请求 if api.example.com/data in flow.request.url: # 直接返回Mock数据不发送到真实服务器 flow.response http.Response.make( 200, b{status:success,data:mocked}, {Content-Type: application/json} )这个简单示例展示了Mitmproxy脚本的基本结构。当检测到目标API请求时它会直接返回预设的JSON响应完全绕过真实服务器。3.2 动态响应生成更高级的用法是根据请求内容动态生成响应def response(flow: http.HTTPFlow) - None: if api.example.com/user in flow.request.url: # 解析请求参数 user_id flow.request.query.get(id, [1])[0] # 生成动态响应 flow.response http.Response.make( 200, f{{id:{user_id},name:User {user_id}}}.encode(), {Content-Type: application/json} )3.3 异常场景模拟自动化测试中经常需要模拟各种异常情况import random def response(flow: http.HTTPFlow) - None: # 随机模拟服务器错误 if random.random() 0.3: # 30%概率触发错误 flow.response http.Response.make( 500, b{error:Internal Server Error}, {Content-Type: application/json} ) # 模拟网络延迟 if api.example.com/slow in flow.request.url: import time time.sleep(3) # 3秒延迟4. 实战构建完整的Mock测试系统4.1 A/B测试接口模拟现代App经常使用A/B测试来优化用户体验。我们可以用Mitmproxy轻松模拟不同的测试分组AB_TEST_CASES { feature_new_ui: { group_a: {enabled: True, color_scheme: dark}, group_b: {enabled: False, color_scheme: light} } } def response(flow: http.HTTPFlow) - None: if api.example.com/ab_test in flow.request.url: user_id hash(flow.client_conn.ip_address) % 2 # 根据IP简单分组 group group_a if user_id 0 else group_b flow.response http.Response.make( 200, json.dumps(AB_TEST_CASES[feature_new_ui][group]).encode(), {Content-Type: application/json} )4.2 自动化测试集成将Mitmproxy Mock服务集成到自动化测试流程中import subprocess import time import pytest pytest.fixture(scopemodule) def start_mock_server(): # 启动Mitmproxy进程 process subprocess.Popen([ mitmdump, --mode, transparent, -s, mock_script.py, --set, listen_port8080 ]) time.sleep(2) # 等待服务器启动 yield process.terminate() def test_app_with_mock(start_mock_server): # 这里运行实际的App测试代码 # 所有网络请求都会被mock_script.py处理 pass4.3 性能测试场景模拟高延迟或低带宽环境def response(flow: http.HTTPFlow) - None: # 为大文件添加延迟 if flow.response and flow.response.content: content_size len(flow.response.content) if content_size 1024*1024: # 大于1MB的文件 import time time.sleep(content_size / (1024*50)) # 模拟50KB/s的网速5. 高级技巧与最佳实践5.1 状态管理有时我们需要在多个请求间保持状态from mitmproxy import ctx class StateManager: def __init__(self): self.user_sessions {} def request(self, flow: http.HTTPFlow) - None: if login in flow.request.url: # 存储登录状态 session_id flow.request.headers.get(Session-ID) if session_id: self.user_sessions[session_id] { logged_in: True, last_active: time.time() } addons [StateManager()]5.2 流量录制与回放实现简单的流量录制功能class Recorder: def __init__(self): self.flows [] def response(self, flow: http.HTTPFlow) - None: self.flows.append({ url: flow.request.url, method: flow.request.method, request: flow.request.text, response: flow.response.text }) def save(self, filename): import json with open(filename, w) as f: json.dump(self.flows, f) recorder Recorder() def done(): recorder.save(recorded_traffic.json)5.3 安全注意事项在使用Mitmproxy进行测试时需要注意证书管理确保测试设备正确安装了Mitmproxy的CA证书敏感数据避免在生产环境使用防止敏感信息泄露性能影响复杂的脚本处理可能引入性能开销# 示例自动拒绝包含敏感信息的请求 SENSITIVE_KEYWORDS [password, credit_card, ssn] def request(flow: http.HTTPFlow) - None: if any(keyword in flow.request.url for keyword in SENSITIVE_KEYWORDS): flow.response http.Response.make( 403, b{error:Sensitive data not allowed in test environment}, {Content-Type: application/json} )在实际项目中我发现最有效的Mock策略是根据测试用例的需求分层设计脚本基础层处理通用的网络异常模拟业务层针对特定功能定制响应逻辑。这种分层方法既保证了灵活性又避免了脚本过于复杂难以维护。