资讯动态

12K测试开发面试高频题:接口、SQL、性能与Redis全解析

发布时间:2026/9/2 17:34:02 来源:尧图企业网站定制
上海12K左右的测试开发岗位面试通常不是单纯考“会不会点按钮”而是把测试基础、代码能力、接口协议、数据库排查、性能分析和工程习惯放在一起综合考察。面试官真正想确认的是给你一个功能或一个线上问题你是否能按正确路径分析、设计、执行并把结论讲清楚。很多候选人准备面试时只背概念比如“等价类是什么”“Redis穿透是什么”但一到现场题就不知道怎么组织答案。原因是面试题背后有固定的考察模型需求理解、测试设计、技术实现、结果验证、问题排查。下面这一组高频题会围绕这五个环节拆解并给出可运行的代码和可复用的答题框架。1. 先理解上海12K测试开发岗位面试的考察逻辑1.1 这个薪资段位到底要什么人12K在上海属于初级到中级的过渡段位。它不需要你上来自带一套测试平台设计经验但也不能只会按测试用例点点点。候选人通常要能独立负责一个模块或一条业务线的测试能写接口自动化脚本能定位简单问题能看懂日志并且能配合开发查数据。换句话说功能测试决定了你能不能入行代码和排查能力决定了你能不能拿到这个薪资。下面这个表格几乎是面试官在筛选简历和设置面试题时的底稿能力维度常见考察方式要达到什么效果测试设计给登录、订单、支付等业务设计用例能覆盖正常、异常、边界、安全、兼容接口能力手写 curl、 Python 请求、断言能独立完成接口级验证数据库能力写 SQL、看执行计划、查慢查询能通过数据判断问题根因Linux 基础查看日志、进程、CPU、内存、磁盘能按链路定位线上问题编程基础字符串、数组、简单算法题能写代码还能为代码写测试1.2 面试流程和题目的常见分布常见一轮技术面试在 40 到 60 分钟题目分布大致是5 到 10 分钟自我介绍和项目问题。10 到 15 分钟测试用例设计或测试理论基础。10 到 15 分钟接口、数据库、Linux 综合题。10 到 15 分钟手写代码或解决实际问题。最后留 5 分钟给候选人反问。项目问题往往比基础题更容易拉开差距。哪怕你过往主要做功能测试也要能把一个项目讲成测试范围是什么、用例怎么设计、执行中发现了什么严重问题、如何定位、最后怎么验证修复。面试官从这段描述里能判断你是否有测试思维和问题闭环能力。1.3 面试官根据什么判断“可以通过”面试官不会因为你一道题答错直接淘汰更多是看你分析过程是否可用。通过的人通常具备这几个特征先澄清需求再开始设计方案不拿到题就闷头写。回答有结构感能按“功能、异常、安全、性能、兼容”分层展开。写代码时考虑空值、边界、异常分支而不是只写主流程。遇到不会的问题不硬编答案而是给出合理排查路径。这个标准决定了后面各个章节的答题重点。准备面试时不要追求“每道题都有标准答案”而要练习“一个问题被追问时我能不能把思考过程讲清楚”。2. 测试用例设计高频题从“写用例”到“讲边界”2.1 一道经典题给登录功能设计测试用例面试题通常是这样的请给一个 Web 登录功能设计测试用例用户名 6 到 20 位密码 8 到 32 位且必须包含字母和数字。很多候选人听到这道题就开始写用户名正确密码正确能否登录、用户名错误密码正确能否登录。写 20 条之后停止。这样容易漏掉关键风险。正确做法是先和面试官确认登录成功后跳转到哪里密码错误有没有次数限制是否包含验证码是 Web 端还是 App 端这些假设会影响用例设计。确认假设后再按类型分层。下面是一个可以现场说出来的用例结构用例类型输入条件预期结果正常流合法用户名和合法密码登录成功并跳转边界值用户名 6 位或 20 位密码 8 位或 32 位登录成功边界值用户名 5 位或 21 位密码 7 位或 33 位提示长度不合法异常流用户名为空或密码为空提示不能为空异常流密码全字母或全数字提示必须包含字母和数字异常流用户名包含特殊字符或中文按需求提示格式错误重复提交快速点击登录按钮多次只发起一次登录请求安全输入 SQL 片段或 HTML 标签后端拒绝不执行脚本兼容不同浏览器、不同分辨率页面功能正常性能多用户同时登录无崩溃、无数据错乱这里的关键是每条用例都要有明确预期结果。只写“输入正确密码”而不写“登录成功并跳转到首页”面试官无法判断你是否真的理解测试设计。2.2 等价类、边界值、场景法怎么用等价类就是把结果相同的数据归成一类不必每个值都测。对上面的登录功能用户名长度合法/不合法密码规则合法/不合法是四个基本等价类。从里面各取一个代表值测试就能覆盖大多数输入。边界值针对长度和范围边界。如果用户名要求 6 到 20 位那么 6、7、20、21 是典型边界。很多缺陷恰恰发生在边界值上因为开发写出类似if (len 6 len 20)这类漏掉等号的情况很常见。场景法则用来验证业务流程。登录功能不能只看单个输入框还要看“正常登录、密码错误三次、连续失败被锁定、找回密码后再登录”这些真实用户路径。基本流加备选流组合起来才能覆盖完整业务。实际项目里这三个方法通常一起用先用等价类砍掉大量冗余数据再用边界值补齐风险点最后用场景法检查业务流程是否通畅。2.3 答题顺序和常见扣分点面试时建议按这个顺序回答先提出假设条件确认需求边界。再按功能、异常、安全、性能、兼容分层。每层给出用例和预期结果。最后根据风险给出重点用例优先级。常见扣分点包括只写正常路径不写空值、超长、重复提交。只写“输入非法字符”不说具体字符范围比如引号、HTML 标签、空字符。只验证前端弹窗忽略后端校验。不提并发登录、密码安全存储、验证码复用等风险。用例写很多但没有优先级面试官看不出你如何分配回归重点。可以在回答中直接说“我会把这个功能分成正常流、异常流、安全流和兼容流四类先保证主路径再补齐高风险场景。”这种结构化表达比零散记忆更有优势。3. 接口测试高频题从命令到代码都要能现场写出3.1 面试官问接口测试时想听到什么接口测试关注的是系统之间的数据交换。面试官想听到的不只是“用 Postman 调接口”而是你清楚接口测试要验证什么请求方法、URL、请求头、请求体是否正确。状态码是否符合预期。业务返回码是否等于预期值。返回 JSON 中的关键字段是否存在、类型和值是否正确。接口对提交的数据做了哪些校验错误分支是否返回明确提示。数据是否真的写入了数据库或者查询是否返回了正确结果。很多功能测试同学只测页面但测试开发必须能从接口层独立验证功能。因为接口层比 UI 层更稳定回归成本更低也是自动化测试投入产出比最高的部分。3.2 手写一个 curl 请求如果面试官要求手写接口请求优先给 curl因为不依赖图形界面能直接说明请求方法、请求头和请求体。下面是一个登录接口的 POST 请求curl -X POST https://api.example.com/login \ -H Content-Type: application/json \ -d {username:test,password:123456}参数说明-X POST指定使用 POST 方法。-H Content-Type: application/json告诉服务端请求体是 JSON。-d {username:test,password:123456}是请求体内容。如果登录后返回 token后续接口需要在请求头里带上可以这样写curl -X GET https://api.example.com/order/1001 \ -H Authorization: Bearer token这里token要替换成实际返回值。面试中能说明“为什么用请求头带 token而不是放在 URL 里”会更好避免 token 出现在访问日志中降低泄露风险。3.3 Python requests pytest 最小接口自动化面试官很可能会追问你除了用工具还能不能写脚本这时候要能现场写出可运行的最小自动化用例。先准备环境python -m venv venv source venv/bin/activate # Windows 下使用 venv\Scripts\activate pip install requests pytest用虚拟环境可以避免污染全局 Python 环境这是工程习惯不是多余动作。然后创建test_login.pyimport requests def test_login_success(): url https://api.example.com/login payload {username: test, password: 123456} resp requests.post(url, jsonpayload) assert resp.status_code 200 data resp.json() assert data[code] 0 assert token in data运行测试pytest test_login.py -v预期输出是test_login.py::test_login_success PASSED这里要特别注意不能只断言status_code 200。很多接口在业务失败时也返回 HTTP 200只是业务 code 不同。接口自动化的核心之一是“业务断言”要校验业务 code 和关键字段。3.4 接口依赖和 token 传递的最简方案接口测试经常遇到依赖关系先登录拿 token再请求业务接口。最简单的方式是使用 pytest fixture在一个会话内只登录一次。创建conftest.pyimport pytest import requests pytest.fixture(scopesession) def token(): resp requests.post( https://api.example.com/login, json{username: test, password: 123456} ) return resp.json()[token]然后测试函数可以直接接收token参数def test_get_order(token): headers {Authorization: fBearer {token}} resp requests.get(https://api.example.com/order/1001, headersheaders) assert resp.status_code 200scopesession表示整个测试会话只执行一次登录后续用例复用 token。生产环境还要处理 token 过期后的自动刷新通常会在请求封装层加“发现 401 后重新登录并重试”的逻辑。注意学习环境可以连接测试环境直接跑脚本但不要用自动化脚本随意压测线上服务。生产环境的接口自动化需要先评估频率、数据隔离和权限范围避免影响真实业务。4. 性能测试高频题指标能背瓶颈要会查4.1 先区分性能测试的类型面试中经常出现这几个词性能测试、负载测试、压力测试、稳定性测试。很多人混着说面试官一听就知道基础不牢。类型目的主要观察指标性能测试验证系统在预期负载下的处理能力响应时间、QPS、资源使用率负载测试逐步加压找到系统性能拐点错误率、响应时间变化压力测试超过预期负载看系统是否稳定是否崩溃、恢复速度稳定性测试长时间运行观察性能趋势内存是否增长、响应是否变慢12K 面试不会要求你设计大规模压测但需要能分清这几个词并能说出“负载测试和压力测试的区别在于是否超过了预期负载”。4.2 核心指标和参考范围性能测试相关的核心指标包括 QPS/TPS、响应时间、并发数、错误率、CPU、内存、磁盘 IO 和网络。指标含义常见定位方式QPS/TPS每秒查询数/每秒事务数压测工具的聚合报告RT响应时间常看平均、p90、p95压测报告、应用日志并发数同一时刻处理的请求数量线程数、连接数错误率失败请求占比压测结果统计CPU处理器忙碌比例top内存已用内存、swap 使用free -h磁盘 IO读写等待、吞吐iostat -x 1网络带宽、连接数sar -n DEV注意参考范围没有统一标准。内部管理系统的接口 p95 可能要求小于 500ms支付场景可能要求小于 200ms。面试时不要报死数值要先说“要看业务目标”再说具体数据。4.3 用 JMeter 压测的完整流程JMeter 是面试中经常被提到的压测工具。完整流程是创建测试计划。添加线程组设置线程数、Ramp-up 时间、循环次数。添加 HTTP 请求填写协议、域名、路径、请求体。添加聚合报告或汇总报告。运行后分析样本数、平均响应时间、吞吐量、错误率。一个简单的线程组配置可能是100 个线程Ramp-up 10 秒循环 2 次。意思是在 10 秒内逐步启动 100 个线程每个线程循环执行 2 次请求。分析结果时不要只看平均值。平均值很容易被极端值掩盖要重点看 p90、p95 和错误率。如果 p95 明显高于平均值说明部分请求已经出现长尾延迟需要进一步定位。生产环境压测要尽量隔离测试数据比如使用影子库或全链路压测标记避免压测请求污染线上真实订单和用户数据。4.4 Linux 下从日志反推性能瓶颈的排查链路面试中常问线上接口突然变慢你怎么定位这个问题没有固定答案但必须有排查顺序。推荐链路是先看日志再看资源再看数据库最后看依赖。第一步看日志。确认超时请求集中在哪个接口、错误码是什么、调用上游服务时耗时多久、有没有抛异常。第二步看资源。用下面几个命令快速检查 CPU、内存、磁盘和 IOtop free -h iostat -x 1 df -htop看 CPU 使用率和负载。free -h看内存和 swap。iostat -x 1看磁盘读写等待如果%util很高磁盘可能是瓶颈。df -h看磁盘空间是否已满。第三步看应用层。如果是 Java 服务可以查 GC 频率和线程状态比如使用jstat -gc看 GC 情况。第四步看数据库。打开慢查询日志用EXPLAIN分析嫌疑 SQL 是否全表扫描、是否索引失效。第五步看依赖。调外部服务、缓存、消息队列的耗时是否有突增。如果 CPU 很高但内存正常可能说明代码在大量计算或出现了死循环如果内存持续走高可能存在内存泄漏如果磁盘 IO 很高可能是日志写入过多或数据库频繁刷盘。性能面试题没有标准答案但必须有排查顺序。先日志再资源再数据库再依赖这样面试官才能沿着你的思路继续追问。5. 数据库与Redis高频题SQL、索引、缓存一致性5.1 一条常见的统计SQL数据库题是测试开发面试的稳定考点。面试官常给一张订单表让你统计每个用户的已完成订单总金额。先建一张简化表CREATE TABLE orders ( id BIGINT PRIMARY KEY, user_id BIGINT NOT NULL, amount DECIMAL(10,2) NOT NULL, status VARCHAR(20) NOT NULL, created_at DATETIME NOT NULL );题目统计每个已完成订单用户的总金额按总金额倒序。SQL 可以这样写SELECT user_id, SUM(amount) AS total_amount FROM orders WHERE status FINISHED GROUP BY user_id ORDER BY total_amount DESC;说明两个关键点WHERE在GROUP BY之前执行先把状态等于FINISHED的订单过滤出来再按用户分组。ORDER BY total_amount DESC使用别名排序按总金额倒序输出。如果需求是“统计每个用户的订单数和总金额”可以加COUNT(*)。写 SQL 时要先确认状态字段的取值和业务口径比如退款订单、未支付订单是否包含在内这比直接背 SQL 更像真实工作。5.2 索引失效的常见原因索引失效是数据库面试的高频追问点。通常遇到的场景包括场景错误示例原因说明对索引列使用函数WHERE date(created_at) 2025-01-01函数处理后无法使用索引隐式类型转换WHERE mobile 13812345678如果 mobile 是 varchar类型转换会阻断索引前导通配符WHERE name LIKE %abc最前面的%导致无法走索引联合索引不满足最左前缀索引(user_id, status)但只查status缺少最左列无法完整使用索引or条件一侧无索引WHERE status OK OR amount 10一张表可能转为全表扫描验证方式是用EXPLAIN查看执行计划EXPLAIN SELECT * FROM orders WHERE user_id 123;面试时能说“我用EXPLAIN看到type是ALLrows很大判断这条 SQL 没有走索引”比单纯背概念更有说服力。5.3 Redis缓存与数据库一致性缓存一致性是测试开发面试中容易答得散的一道题。比较常见的方案是先更新数据库再删除缓存。为什么是删除而不是更新缓存因为更新缓存时如果两个线程同时写可能出现线程 A 写成新值、线程 B 再覆盖成旧值的情况。删除缓存虽然也可能出现并发问题但配合缓存过期时间脏数据影响可以被限制。一个常见问题时序如下线程 A 把数据库更新为 100。线程 A 删除缓存。线程 B 请求数据缓存 miss。线程 B 从数据库读到旧值 50回填缓存。后续请求读到旧缓存出现脏数据。解决思路通常是给缓存设置过期时间兜底一致性问题。使用延迟双删删除缓存后等待几百毫秒再删一次。或者引入版本号回填缓存时比较版本。面试时不要笼统说“保证强一致”。对大多数业务来说数据库和缓存做到最终一致并配合过期时间已经足够。强一致需要引入版本号、消息队列或分布式锁成本更高适用场景也更窄。5.4 慢SQL排查路径慢 SQL 排查是测试开发日常工作中很常见的任务。排查顺序可以这样做打开慢查询日志并设置阈值。抓取慢 SQL用EXPLAIN分析执行计划。关注type、key、rows字段判断是否全表扫描。检查是否需要加索引或者是否存在索引失效场景。检查分页查询是否出现深翻页比如LIMIT 100000, 20。开启慢查询日志的示例SET GLOBAL slow_query_log ON; SET GLOBAL long_query_time 1;这里把超过 1 秒的 SQL 记为慢查询。生产环境开启慢查询要关注日志磁盘空间建议设置合理的阈值并定期归档。加索引也要谨慎。生产环境数据量大的时候在线加索引可能会锁表或消耗大量 IO一般建议在业务低峰期执行并提前评估磁盘空间和耗时。6. 测试开发编程题代码能力和测试思维一起考6.1 为什么面试官喜欢考字符串转换测试开发岗位的编程题通常不会出特别复杂的算法而是考字符串、数组、链表、简单递归。手写parse_int这类题目尤其常见因为一个函数里同时包含了输入校验、边界值、异常处理和测试开发日常工作高度重合。候选人写完代码后面试官还会接着问你怎么测试它如果你能在写出实现后继续给出覆盖正常、异常、边界的测试用例就已经完成了“开发 测试”完整闭环。6.2 实现 parse_int题目不使用 Python 内置的int()实现一个字符串转整数函数需要处理空字符串、正负号、空格、非法字符。一个可运行的实现如下def parse_int(s: str) - int: if s is None or s.strip() : raise ValueError(empty input) s s.strip() sign 1 i 0 if s[0] in (, -): if s[0] -: sign -1 i 1 if i len(s): raise ValueError(only sign) result 0 for ch in s[i:]: if not 0 ch 9: raise ValueError(finvalid char: {ch}) result result * 10 (ord(ch) - ord(0)) return sign * result关键点解释先处理None和空字符串这是输入校验的第一层。strip()去掉首尾空格符合多数实际接口的容错要求。和-只出现在首位且不能只有符号。逐字符判断是否为数字ord(ch) - ord(0)得到数字值不需要int()。遇到非法字符直接抛出ValueError方便调用方知道失败原因。Python 的int没有 32 位溢出问题但很多面试题希望模拟 Java 或 C 语言环境要求判断 32 位整数范围。此时需要在循环里增加越界检查MAX_INT 2**31 - 1 # 在循环内 if sign 1 and result MAX_INT: raise OverflowError(int overflow) if sign -1 and result 2**31: raise OverflowError(int overflow)这里要注意负数范围是-2^31绝对值上限是2^31所以负数判断时不能用MAX_INT这是代码题里非常容易踩的坑。6.3 为 parse_int 编写测试用例写完实现后主动补测试用例是测试开发岗位最好的加分项。下面用 Python 标准库unittest编写import unittest class TestParseInt(unittest.TestCase): def test_normal_positive(self): self.assertEqual(parse_int(123), 123) def test_negative_with_sign(self): self.assertEqual(parse_int(-42), -42) def test_plus_sign(self): self.assertEqual(parse_int(7), 7) def test_space_around(self): self.assertEqual(parse_int( 88 ), 88) def test_empty_raises(self): with self.assertRaises(ValueError): parse_int() def test_invalid_char_raises(self): with self.assertRaises(ValueError): parse_int(12a3) def test_sign_only_raises(self): with self.assertRaises(ValueError): parse_int(-) if __name__ __main__: unittest.main()运行后预期结果. ---------------------------------------------------------------------- Ran 7 tests in 0.001s OK这些用例覆盖的维度可以整理成一张表用例类型示例验证点正常正数123基本转换正确负数-42负号处理正确正号7正号允许首尾空格 88 容错处理空字符串必须报错非法字符12a3必须报错只有一个符号-必须报错写题时可以先跟面试官确认是否需要 32 位范围限制再决定是否加入OverflowError。确认需求后再写代码这本身就是好的工程习惯。6.4 写题时的表达顺序面试现场写代码表达顺序和代码同样重要。建议按下面流程走先确认函数输入输出和限制条件比如是否允许空格、是否需要越界。用自然语言描述思路比如“先处理符号再逐位转换”。再写关键实现。写完后主动说我要用哪些测试用例来验证。最后跑一遍测试把结果讲给面试官。不要一上来就写正则表达式因为正则虽然简洁但可读性差且容易漏掉边界场景。先能写出清晰实现再讨论优化。7. 面试现场常见坑答错不是最可怕的

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

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

免费获取报价