资讯动态

听书App测试实战:接口测试、UI自动化与性能压测

发布时间:2026/10/1 16:42:18 来源:尧图企业网站定制
1. 项目缘起与测试范围拆解1.1 为什么选一个听书App作为测试实战标的很多人找测试项目练手第一反应是电商后台或者管理系统。这类项目确实经典但问题也很明显同质化严重面试官一听就知道是教程里的东西问不出深度。我选择“不爱听书”这个项目做测试实战恰恰是因为它的业务形态比普通增删改查复杂——它融合了音频流媒体、用户行为追踪、书架同步、离线缓存这四类典型移动端难题。听书App的核心链路是“搜索→试听→加入书架→断点续传→倍速播放→定时关闭”每一步都涉及前端、后端、音频引擎、本地数据库的多方交互非常适合拿来练习接口测试、UI自动化、性能压测。这个项目源码是基于前后端分离架构搭的前端是Vue2的移动端页面加Android原生壳后端是SpringBoot提供RESTful接口音频文件走对象存储直链或者CDN分发。测试范围覆盖了账号体系、书籍管理、播放控制、社交分享、支付订阅五大模块。你拿到源码之后不需要从零写业务代码只需要聚焦在“怎么测”上。说实话市面上能把测试教程和可运行源码绑在一起的项目不多大部分只给PPT或者视频你照着敲完还是不知道真实项目长什么样。这个项目的价值就在于源码可跑、接口可调、数据库可查你能看到真实的数据流转而不是对着Mock数据瞎猜。1.2 技术栈速览与测试切入点先把这个项目的技术栈理清楚不然你连日志都看不懂。后端SpringBoot 2.x MyBatis-Plus MySQL 8 Redis MinIO存音频和封面。前端Vue 2 Vant UI Axios移动端壳是Android WebView加原生音频组件。接口风格是标准的RESTful JSON登录鉴权用JWTToken放在Header的Authorization字段里。测试切入点我建议按这个顺序来先把接口层跑通再做UI自动化最后补性能和安全。为什么这么排因为UI测试依赖数据准备数据准备靠接口调用最快而且接口测试的投入产出比最高一个脚本能覆盖几十个用例。提示拿到源码后先别急着写用例用Postman把登录、获取书籍列表、加入书架这三个接口手动调通。这一步能帮你确认环境是否正常省去后面排查环境问题的时间。1.3 测试环境搭建清单与避坑要点搭建环境是新手最容易卡住的地方。我把需要的工具列一下版本尽量对齐不然会出现莫名其妙的依赖冲突。JDK用1.8或者11Maven 3.6以上MySQL 5.7或8.0Redis 5以上Node.js 14到16之间Vue2对高版本Node兼容性一般。Android端测试需要Appium 1.22左右配合UiAutomator2驱动。特别注意MySQL 8的连接URL要加serverTimezoneAsia/Shanghai否则后端启动会报时区错误Redis如果设了密码配置文件里要同步改不然Token校验会失败。我踩过的坑是MinIO的Endpoint配置——源码里写的是内网地址你本地跑要改成127.0.0.1:9000并且提前建好bucket否则上传封面图会返回403。# 后端启动前先确认三个服务 mysql -uroot -p -e show databases; # 确认不爱听书的库存在 redis-cli ping # 返回PONG curl http://127.0.0.1:9000/minio/health/live # MinIO健康检查环境通了之后用浏览器访问后端Swagger地址通常是/doc.html或/swagger-ui.html能看到接口列表就说明后端OK。前端用npm run serve启动手机模拟器访问http://你的IP:8080。这里注意Android模拟器访问本机要用10.0.2.2而不是localhost这个细节能让你少查半小时资料。2. 接口测试实战从手工调通到脚本覆盖2.1 接口清单梳理与优先级划分打开Swagger或者抓包工具先把接口按模块列出来。我一般用Excel或者在线文档建一个接口清单表字段包括接口路径、请求方法、入参、出参、依赖关系、优先级。不爱听书这个项目大概有40多个接口但核心链路只有十几个。优先级怎么定P0是登录、书籍列表、播放地址获取、书架增删这些挂了整个App就废了P1是搜索、评论、分享、订阅状态查询P2是历史记录、偏好设置、意见反馈。先做P0保证主流程能跑通再做P1补充场景。模块核心接口方法鉴权优先级用户/api/user/loginPOST否P0书籍/api/book/listGET是P0播放/api/play/url/{bookId}GET是P0书架/api/shelf/addPOST是P0搜索/api/searchGET是P1评论/api/comment/addPOST是P12.2 用RequestsPytest搭建接口测试骨架手工调通之后立刻转成自动化脚本不然每次回归都要点一遍时间全浪费在重复劳动上。我用的组合是Python的Requests库加Pytest框架再加Allure出报告。目录结构这样分common放配置和日志api放接口封装testcases放用例data放测试数据。先写一个BaseApi类处理Token和公共请求头后面所有接口继承它。import requests class BaseApi: def __init__(self): self.base_url http://127.0.0.1:8080 self.session requests.Session() self.token None def login(self, username, password): url f{self.base_url}/api/user/login payload {username: username, password: password} resp self.session.post(url, jsonpayload) self.token resp.json()[data][token] self.session.headers.update({Authorization: self.token}) return resp这段代码里有个细节值得说用requests.Session()而不是每次requests.post()因为Session会自动保持Cookie而且连接池复用能提升执行速度。Token拿到后统一塞进headers后续接口就不用每个都传了。登录密码在源码里通常是MD5加盐存的测试环境的账号密码可以查数据库的user表或者直接看源码里的初始化SQL。2.3 参数化与数据驱动的落地方法接口用例最怕写死数据。比如“加入书架”这个接口如果你每次都用bookId1跑第二遍就可能因为重复添加而失败。解决办法是数据驱动把测试数据放在YAML或者CSV里用Pytest的pytest.mark.parametrize注入。我一般会准备三组数据正常值、边界值、异常值。以书架添加为例正常值是有效bookId边界值是书架数量达到上限源码里限制200本异常值是bookId不存在或者负数。import pytest import yaml from api.shelf_api import ShelfApi def load_data(): with open(data/shelf_data.yaml) as f: return yaml.safe_load(f) pytest.mark.parametrize(case, load_data()) def test_add_shelf(case): api ShelfApi() api.login(tester, 123456) resp api.add_shelf(case[bookId]) assert resp.json()[code] case[expect_code]注意每次执行前要清理测试账号的书架数据否则用例会相互污染。我习惯在conftest.py里写一个fixture登录后先调删除接口把书架清空这个“前置清理”能解决80%的偶发失败。2.4 接口断言策略与常见陷阱新手写断言往往只看HTTP状态码200就过了这是大忌。真实的接口测试要分三层断言HTTP状态码、业务状态码、数据字段内容。不爱听书的接口返回体是{code:0,msg:success,data:{...}}所以你要断言code等于0还要断言data里的关键字段符合预期。比如获取播放地址接口data里要有audioUrl且以http开头duration要大于0。另一个陷阱是时间戳和随机数——有些接口返回的orderNo或者traceId每次不同断言时要用正则或者只判断长度。还有分页接口第一页的数据条数要等于pageSize最后一页要小于等于pageSize这个边界很容易漏测。3. UI自动化测试移动端页面元素定位与稳定性3.1 移动端自动化方案选型对比移动端UI自动化有三条路Appium、Airtest、UiAutomator原生。Appium跨语言跨平台社区资料最多适合这个项目Airtest基于图像识别对游戏或者Canvas渲染友好但维护成本高UiAutomator只支持Android且要写Java。我选Appium加Python客户端原因是源码里的Android壳是标准WebView加原生控件Appium能自由切换Native和WebView上下文定位方式灵活。版本搭配Appium Server 1.22.3appium-python-client 2.xUiAutomator2驱动。注意Appium 2.x之后驱动要单独安装命令是appium driver install uiautomator2这个变化让很多人卡在启动环节。3.2 元素定位的优先级与实战代码定位元素的原则是ID Accessibility ID XPath Class Name。ID最稳XPath最灵活但最容易碎。不爱听书的播放页有个“播放/暂停”按钮源码里通常有resource-id优先用它。如果拿不到ID用content-descAccessibility ID也比XPath强。实在要用XPath尽量用相对路径加属性组合避免绝对路径。下面是一个登录加播放的示例from appium.webdriver.common.appiumby import AppiumBy def test_play_audio(driver): driver.find_element(AppiumBy.ID, com.buaishu:id/et_username).send_keys(tester) driver.find_element(AppiumBy.ID, com.buaishu:id/et_password).send_keys(123456) driver.find_element(AppiumBy.ID, com.buaishu:id/btn_login).click() # 等待首页加载 driver.implicitly_wait(10) driver.find_element(AppiumBy.XPATH, //*[text三体]).click() play_btn driver.find_element(AppiumBy.ID, com.buaishu:id/btn_play) play_btn.click() assert play_btn.get_attribute(selected) true3.3 等待机制与滑动操作的坑移动端最大的敌人是网络延迟和动画。你刚点完登录下一页还没渲染出来脚本就去找元素必然报NoSuchElement。解决办法是用显式等待WebDriverWait替代强制等待sleep。比如等待“我的书架”标题出现最多等15秒每0.5秒查一次。另外列表滑动不要用坐标硬滑用driver.swipe()在不同分辨率手机上会失效。推荐用UiAutomator的scroll方法或者Appium的touch_action配合元素定位。还有一个坑WebView里的元素需要先driver.switch_to.context(WEBVIEW_com.buaishu)操作完再切回NATIVE_APP忘了切回来后面全部报错。实操心得调试脚本时打开Appium Inspector它能实时查看页面元素树。但是注意Inspector会和你的脚本抢驱动端口调试完要关掉Inspector再跑脚本否则报“session is already running”。3.4 测试用例分层与数据清理UI用例不要写成一条超长流程要分层。我分成三类冒烟用例登录→搜索→播放→退出、功能用例每个页面独立验证、异常用例断网、空数据、权限拒绝。每类用例执行前用BeforeMethod重置App状态用driver.reset()或者adb shell pm clear清数据。数据清理同样重要UI操作产生的书架数据、历史记录要删掉不然下次跑用例首页全是脏数据。我的做法是UI用例跑完后调一次接口把账号数据重置这比在UI上点删除快得多也稳定得多。4. 性能压测与专项测试的取舍4.1 听书App的性能指标该盯哪几个性能测试不是所有项目都要做但听书App有两个指标绕不开音频首播加载时间和并发播放稳定性。首播加载时间指从点击播放到声音出来的间隔超过3秒用户就会烦躁超过5秒直接卸载。并发播放稳定性指100人同时请求音频流时服务端带宽和CDN回源是否扛得住。用JMeter做压测线程组设100Ramp-up设10秒循环5次监控TPS和响应时间。源码里音频走MinIO直链压测时你会发现瓶颈往往在磁盘IO或者带宽而不是CPU。如果响应时间随并发数线性上升说明带宽打满了如果突然大量报错检查MinIO的连接数配置。4.2 弱网模拟与断点续传验证移动端专项测试里弱网是必测项。用Charles或者Fiddler设置限速模拟2G/3G/4G和丢包场景。重点验证断点续传播放到30秒时断网恢复后能不能从30秒继续而不是从头开始。源码里断点续传依赖本地数据库记录播放位置测试时要检查SharedPreferences或者SQLite里的position字段有没有更新。我遇到过恢复网络后位置没同步的Bug原因是后台线程被杀死位置没写进去。这种问题只能靠专项测试发现功能测试覆盖不到。4.3 兼容性测试的轻量方案兼容性测试不等于买一堆手机。预算有限的话用Android模拟器覆盖主流分辨率720P、1080P、2K和Android版本7.0、10、13再用云测平台补几台真机。重点看三个地方播放页布局是否错位、音频焦点切换是否正常、后台播放是否被杀死。音频焦点问题是听书App特有的——你正听着书来了一个电话挂断后能不能自动恢复播放。这个在源码里通常用AudioManager处理测试时要专门设计用例覆盖。5. 实战答疑与避坑速查5.1 常见问题排查表问题现象可能原因排查步骤后端启动报时区错误MySQL URL缺serverTimezone加serverTimezoneAsia/Shanghai登录返回401Token未带或过期检查Header的Authorization字段播放无声音MinIO音频地址403检查bucket权限和Endpoint配置Appium找不到元素未切换WebView上下文switch_to.context切换压测TPS上不去带宽或磁盘IO瓶颈看服务器监控升级带宽或换SSD书架数据重复用例未清理前置数据conftest里加清理fixture5.2 面试中怎么讲这个项目这个项目拿去找工作面试官一定会问“你测了什么发现了什么Bug”别只说“我写了多少用例”要说业务价值。比如“我发现播放页在弱网下断点续传失败定位到是本地位置写入被后台线程竞争锁阻塞修复后用户流失率预估降低X%。”这种回答有场景、有定位过程、有影响分析比背测试理论强十倍。另外准备好两个数据接口自动化覆盖率比如核心接口80%、UI自动化节省的回归时间比如从2小时缩到20分钟。数字最直观。5.3 源码二次开发的测试扩展拿到源码别只跑一遍就完事试着改点东西再测。比如把书架上限从200改成500看前端有没有同步改校验把音频码率调高看弱网下卡顿是否加剧。这种“破坏性测试”能锻炼你的测试思维。还有一个方向是接入CI/CD用Jenkins拉代码、跑接口脚本、出Allure报告、发邮件通知。整套流程跑通之后你对“测试左移”和“持续集成”的理解会完全不一样这才是项目实战的真正价值。最后分享一个我踩过的坑跑UI自动化时模拟器突然卡死脚本报“socket hang up”。后来发现是模拟器内存分配太小改成4G内存加2核CPU后稳如老狗。所以环境配置别抠门该给的资源要给够否则调脚本的时间比写脚本还长。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑