不止于抓包:用Python+Mitmproxy在Mac上打造自动化测试代理服务器
当测试工程师需要验证移动应用在不同网络条件下的表现时,传统的手动测试方法往往效率低下。想象一下这样的场景:你需要测试当API返回特定错误码时,App是否能正确处理;或者需要模拟高延迟网络环境来验证加载动画是否正常显示。这些重复性工作如果全部手动操作,不仅耗时耗力,而且难以保证测试的一致性。
这就是Mitmproxy结合Python脚本能力的用武之地。作为一个轻量级、可编程的中间人代理工具,Mitmproxy不仅能拦截和查看网络请求,更能通过编写Python脚本实现请求/响应的自动化修改、性能监控和断言验证。本文将带你从零开始,在Mac上构建一个功能完善的自动化测试代理服务器,并将其集成到CI/CD流程中。
1. 环境准备与基础配置
在开始编写自动化测试脚本前,我们需要确保Mitmproxy环境正确配置。以下是Mac上的安装步骤:
# 使用Homebrew安装Mitmproxy brew install mitmproxy # 验证安装是否成功 mitmproxy --version安装完成后,你会遇到第一个挑战:如何让移动设备信任Mitmproxy的CA证书。不同于浏览器,移动应用默认不会信任用户安装的证书,这会导致HTTPS流量无法被解密。
解决方法是在设备上手动安装并信任证书:
- 确保测试设备和Mac处于同一局域网
- 在设备浏览器访问
mitm.it - 下载对应操作系统的证书并安装
- 在系统设置中完全信任该证书
注意:iOS设备需要在"设置 > 通用 > 关于本机 > 证书信任设置"中启用对Mitmproxy证书的完全信任
2. 透明代理模式配置
要让所有网络流量(包括非HTTP协议)都经过Mitmproxy,我们需要配置透明代理模式。这比普通代理模式更加强大,但也更复杂。
# 启用IP转发 sudo sysctl -w net.inet.ip.forwarding=1 # 创建PF规则文件 echo "rdr pass on en0 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 8080" | sudo pfctl -ef - # 加载PF规则 sudo pfctl -f /etc/pf.conf sudo pfctl -e常见问题及解决方案:
| 问题现象 | 可能原因 | 解决方案 |
|---|---|---|
| 设备无法上网 | PF规则未生效 | 检查网卡名称(en0/bridge100)是否正确 |
| HTTPS流量无法解密 | 证书未正确安装 | 重新安装并信任证书 |
| 部分请求被跳过 | 应用使用了证书绑定 | 修改应用代码或使用Frida绕过 |
3. 编写自动化测试脚本
Mitmproxy的强大之处在于其Python API。我们可以编写mitmHandler.py来实现各种自动化测试场景。
3.1 修改API响应
以下脚本演示如何拦截特定API请求并修改其响应:
from mitmproxy import http def response(flow: http.HTTPFlow) -> None: if "/api/user/profile" in flow.request.pretty_url: # 修改响应状态码 flow.response.status_code = 404 # 修改响应体 flow.response.content = b'{"error": {"code": 404, "message": "User not found"}}'3.2 模拟网络延迟
测试弱网环境时,我们可以人为添加延迟:
import time def request(flow: http.HTTPFlow) -> None: if "checkout" in flow.request.path: # 模拟2秒网络延迟 time.sleep(2)3.3 自动化断言
在持续集成中,我们可以自动验证API响应是否符合预期:
def response(flow: http.HTTPFlow) -> None: if "/api/products" in flow.request.url: assert flow.response.status_code == 200 assert "application/json" in flow.response.headers["Content-Type"] assert len(flow.response.json()["products"]) > 04. 集成到CI/CD流程
要让自动化代理测试成为持续集成的一部分,我们需要解决几个关键问题:
- 证书管理:将Mitmproxy CA证书预置到测试镜像中
- 服务启动:在CI脚本中自动启动Mitmproxy
- 结果收集:将拦截的请求和测试结果保存为报告
以下是一个GitLab CI的配置示例:
stages: - test mitmproxy_test: stage: test script: - brew install mitmproxy - mitmdump --mode transparent -s mitmHandler.py --set console_eventlog_verbosity=info & - xcodebuild test -project MyApp.xcodeproj -scheme MyApp -destination 'platform=iOS Simulator,name=iPhone 13' artifacts: paths: - .mitmproxy/*.log5. 高级应用场景
5.1 多设备并行测试
通过修改PF规则,我们可以让多个设备同时使用同一个Mitmproxy实例:
# 为每个设备创建独立的端口转发规则 echo "rdr pass on en0 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 8080" | sudo pfctl -ef - echo "rdr pass on en1 inet proto tcp to any port {80, 443} -> 127.0.0.1 port 8080" | sudo pfctl -ef -5.2 流量录制与回放
Mitmproxy支持将流量保存为文件供后续分析或回放:
def done(): # 测试结束时保存所有流量 with open("traffic.mitm", "wb") as f: f.write(mitmproxy.io.FlowWriter(f).dumps(flows))5.3 性能监控
我们可以收集各项性能指标并发送到监控系统:
def response(flow: http.HTTPFlow) -> None: metrics = { "url": flow.request.url, "duration": flow.response.timestamp_end - flow.request.timestamp_start, "size": len(flow.response.content) } send_to_monitoring(metrics)在实际项目中,我们发现最常遇到的挑战是处理证书绑定(Pinning)的应用。这时可以结合Frida等工具来绕过安全限制,或者更好的方案是,在测试构建中主动禁用证书绑定。