news 2026/6/4 21:34:25

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

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
不止于抓包:用Mitmproxy + Python脚本实现iOS/Android App自动化测试数据Mock

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

在移动应用开发的生命周期中,自动化测试是确保产品质量的关键环节。然而,传统的测试方法往往受限于后端服务的稳定性和多样性,难以模拟复杂的网络环境和异常数据场景。这正是Mitmproxy结合Python脚本大显身手的领域——它不仅是一个抓包工具,更是自动化测试中数据Mock的瑞士军刀。

想象一下这样的场景:你需要测试App在网络延迟时的表现,或者验证它对异常API响应的容错能力。传统方法可能需要修改后端代码或搭建复杂的测试环境,而Mitmproxy+Python的方案则可以在不修改任何生产代码的情况下,动态拦截和修改网络请求,实现各种测试场景的快速模拟。本文将带你深入这一技术组合的高级应用,从原理到实践,构建一个完整的Mock服务解决方案。

1. Mitmproxy在自动化测试中的核心优势

Mitmproxy之所以成为自动化测试的利器,源于其独特的架构设计和工作原理。与常见的抓包工具不同,Mitmproxy是一个基于Python开发的中间人代理,提供了完整的API用于编程式地操控网络流量。

三大核心能力使其在测试领域脱颖而出:

  • 实时流量拦截与修改:可以在请求到达服务器前或响应返回客户端前进行动态修改
  • 脚本化控制:通过Python脚本实现复杂的流量处理逻辑
  • 多协议支持:不仅支持HTTP/HTTPS,还能处理WebSocket等现代协议

对比其他方案,Mitmproxy的最大优势在于其灵活性。例如,传统的Mock服务器需要预先定义所有可能的响应,而Mitmproxy可以根据运行时条件动态生成响应。这在需要模拟大量测试用例或复杂业务逻辑时尤其有价值。

提示:Mitmproxy的透明代理模式特别适合移动端测试,因为它不需要修改App代码或配置,只需设置设备网络即可生效。

2. 环境搭建与基础配置

2.1 安装与基本配置

在Mac上安装Mitmproxy非常简单,推荐使用Homebrew:

brew install mitmproxy

对于Python脚本支持,建议创建一个虚拟环境:

python -m venv mitm-env source mitm-env/bin/activate pip install mitmproxy

2.2 透明代理与正向代理的选择

在移动测试场景中,我们通常面临两种代理模式选择:

特性透明代理正向代理
设备配置需修改网络设置需在App或系统中配置代理
适用场景无法修改代理设置的App可控制代理配置的环境
复杂度初始配置复杂配置简单
兼容性可能遇到证书问题证书管理更直观

对于iOS/Android设备测试,透明代理通常是更好的选择,因为它不需要修改App本身。以下是配置透明代理的关键步骤:

# 启用IP转发 sudo sysctl -w net.inet.ip.forwarding=1 # 设置端口转发规则 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.py

3. 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(scope="module") def start_mock_server(): # 启动Mitmproxy进程 process = subprocess.Popen([ "mitmdump", "--mode", "transparent", "-s", "mock_script.py", "--set", "listen_port=8080" ]) time.sleep(2) # 等待服务器启动 yield process.terminate() def test_app_with_mock(start_mock_server): # 这里运行实际的App测试代码 # 所有网络请求都会被mock_script.py处理 pass

4.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策略是根据测试用例的需求分层设计脚本:基础层处理通用的网络异常模拟,业务层针对特定功能定制响应逻辑。这种分层方法既保证了灵活性,又避免了脚本过于复杂难以维护。

版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/4 21:32:40

WiiM Bar 7 月发布:479 美元打破高音质高价魔咒,拓展全屋音频生态

WiiM Bar&#xff1a;高性价比拓展全屋音频生态 音频公司 WiiM 即将于 7 月发布 WiiM Bar 条形音箱&#xff0c;旨在拓展其全屋音频生态系统。这款产品打破了“高音质需高额投入”的观念&#xff0c;以 479 美元的实惠价格&#xff0c;提供丰富的流媒体选项和可扩展性&#xff…

作者头像 李华
网站建设 2026/6/4 21:20:40

OpencvSharp 算子学习教案之 - Cv2.RotatedRectangleIntersection 重载2

OpencvSharp 算子学习教案之 - Cv2.RotatedRectangleIntersection 重载2 大家好&#xff0c;Opencv在很多工程项目中都会用到&#xff0c;而OpencvSharp则是以C#开发与实现的Opencv操作库&#xff0c;对.NET开发人员友好&#xff0c;但很多API的中文资料、应用场景及常见坑点等…

作者头像 李华
网站建设 2026/6/4 21:20:36

如何让 GORM 打印 SQL 语句?三种方式全解析

前言 在使用 GORM 开发 Go 项目时&#xff0c;经常需要查看实际执行的 SQL 语句——排查慢查询、调试数据逻辑、确认查询条件是否正确……但 GORM 默认是关闭的&#xff0c;不会主动把 SQL 打印出来。方式一&#xff1a;全局开启 Debug 模式(最简单) GORM 提供了一个非常方便的…

作者头像 李华
网站建设 2026/6/4 21:16:01

AI时代,程序员焦虑升级:是内卷CRUD还是借力AI?35岁危机如何破局?

文章指出AI正改变程序员的工作方式&#xff0c;引发新的焦虑&#xff1a;被替代的风险和经验的有效性。作者强调&#xff0c;未来程序员需从重复性劳动中解放&#xff0c;转向高价值任务&#xff0c;如业务理解、架构把控和复杂问题解决。AI将承担写代码等基础工作&#xff0c;…

作者头像 李华