1. 笔试整体情况与题型分布
腾讯音乐秋招技术测试岗的笔试,第一批安排在九月中旬,线上双机位,平台用的牛客网。整个考试时长 120 分钟,题量不算夸张,但时间依然紧张,尤其是场景设计题非常考验临场思路。
我当时提前二十分钟进系统检查摄像头和环境,确认桌面没有多余软件才敢点开始。这里先说结论:这套笔试题的核心不是考你背了多少东西,而是考你的测试思维和工程判断力。和纯开发的笔试不一样,测试岗的题会明显偏向“能不能发现别人发现不了的问题”“能不能把一个问题拆成可执行的用例”,这是整张卷子的灵魂。
岗位方向是技术测试岗,不是普通的功能测试,所以对代码能力、系统原理、数据库和网络基础都有要求。卷子分为四大部分:计算机基础选择题、编程题、数据库与 SQL 题、测试场景设计题。
题型分布大致如下表:
| 模块 | 题量 | 建议用时 | 重点考察方向 |
|---|---|---|---|
| 选择题(单选+多选) | 25 道 | 30 分钟 | 数据结构、操作系统、网络、测试理论 |
| 编程题 | 2 道 | 45 分钟 | 字符串处理、队列/栈、边界条件 |
| SQL 题 | 1 道大题 | 15 分钟 | 表关联、聚合查询、时序数据统计 |
| 测试场景设计题 | 2 道 | 30 分钟 | 用例设计、异常分析、测试优先级 |
适合谁看这份复盘?如果你是准备互联网大厂测试开发/测试工程师校招的应届生,或者想从功能测试转技术测试的从业者,这篇内容会对你帮助很大。我尽量把当时的解题思路、踩坑细节、甚至评分逻辑都讲透,而不是简单列个题目清单。
说实话,第一批笔试的难度属于“中等偏上”,比简单刷题能应付的程度要高,但远没到竞赛级别。重点在于你能不能跳出背诵式的答题习惯,用测试工程师的职业思维去思考每一个问题。
2. 计算机基础选择题:覆盖范围与答题策略
2.1 数据结构与算法基础
选择题里数据结构大概占 6-7 道,难度不大,但覆盖面广。当时遇到的题目涉及哈希表冲突处理、二叉树遍历、堆的调整过程、栈在表达式求值中的应用、链表与数组的适用场景对比。
印象深刻的一道题是关于哈希表冲突的:题干给了线性探测法和链地址法两种方式,问在负载因子 0.75 的情况下,哪一种方式的查找平均时间复杂度更稳定。其实就是考你链表退化和线性探测集群效应的基本原理。
我的经验是:不需要背八股文,但一定要理解数据结构的本质。比如栈常用于括号匹配和函数调用,队列常用于 BFS 和消息缓冲,这些都是原则性的判断依据。做题时先画图,把抽象的数据操作转化为具象的流程,出错率会低很多。
2.2 操作系统与并发基础
操作系统这块大概是 5-6 道题,集中在进程与线程的区别、死锁的四个必要条件、虚拟内存与分页机制、进程间通信方式。
我们测试岗特别关注并发场景,所以有一道经典的死锁题:两个线程各自持有一把锁,同时尝试获取对方的锁,问最终会发生什么,以及如何避免。这就是考死锁的互斥、持有并等待、不可剥夺、循环等待四个条件。
答题时注意“破坏循环等待条件”是最实用也最常见的死锁规避手段——给锁编号,强制按顺序获取。这道题在选择题里出现,后面场景设计题里也可能间接用到,因为测试需要从场景反推系统设计的问题。
另外还考了一道关于线程池参数的题,问阻塞队列满了之后,再提交任务会走什么策略。这是 Java 线程池的经典问题,但即使你用的是 Python 或 Go,也应该理解这个模型:核心线程数、最大线程数、阻塞队列、拒绝策略,这四者共同决定了一个系统在洪峰流量下的行为。
2.3 计算机网络基础
网络题大概 4-5 道,TCP/IP 协议栈是重中之重。当时考了 TCP 三次握手状态变化、HTTP 状态码语义、TCP 与 UDP 的区别、DNS 解析过程。
HTTP 状态码那题比较实用:题目给了 301、302、304、403 四个状态码,问哪些属于重定向类。考察点很清晰,301 永久重定向、302 临时重定向、304 未修改缓存协商,403 是服务器拒绝请求。作为测试,你平时抓包看接口返回时,这些状态码的含义必须烂熟于心。
TCP 四次挥手的状态变化,TIME_WAIT 出现在主动关闭方,这个知识点也考了。和开发岗不同,测试岗追问 TIME_WAIT 的意义,是要你理解连接关闭后的资源释放机制,以及大量短连接场景下 TIME_WAIT 过多会带来什么影响——这直接关联到性能测试中的连接池优化问题。
2.4 测试理论基础
这一部分才是真正的“分水岭”。约 5 道题直接考测试知识,包括黑盒白盒测试的区别、边界值分析和等价类划分的应用场景、测试用例的覆盖率评估、Bug 优先级定义等。
有一道题很典型:一个输入框规定只能输入 0-100 的整数,问以下哪一组测试数据最符合边界值分析法。正确答案涉及 -1、0、1、99、100、101 这类边界附近的取值。这个知识点不只是笔试用,实际工作中写用例,边界值分析是最高效的用例设计方法之一。
另外一道多选考缺陷(bug)的严重级别与优先级的区别。这两个概念常被混淆,严重级别指缺陷对系统造成的破坏程度,优先级指修复缺陷的先后顺序。A bug 严重但可能优先级低(比如极端条件下的严重 Bug),B bug 不严重但优先级高(比如影响核心流程的样式错乱),这种题非常“实战”。
做这部分选择题有一个核心策略:遇到不确定的多选题,宁愿少选,不要多选。多选错选是零分,漏选还能拿部分分。我当时的策略是先做会做的,拿不准的跳过标记,最后再回头思考,保证整体节奏不受影响。
3. 编程题:算法实现与测试视角
3.1 第一题:字符串去重与排序
编程题总共两道,第一道相对简单,题目要求实现一个函数:给定一个字符串,去除其中重复的字符,保持第一次出现的顺序,并输出按 ASCII 码升序排序后的结果。
先注意,这个需求可以有两种理解:一是去重后保留原顺序,二是去重后排序输出。题目原文是“去除重复字符后,按照字符 ASCII 码升序输出”。我当时差点就按保留原顺序来实现了,后来仔细读题才发现要排序。
def deduplicate_and_sort(s: str) -> str: seen = set() result = [] for ch in s: if ch not in seen: seen.add(ch) result.append(ch) result.sort(key=lambda c: ord(c)) return ''.join(result)这里有一个细节:Python 的set是哈希结构,O(1) 时间复杂度判断重复,整个算法的时间复杂度为 O(n log n),空间复杂度为 O(n)。面试官比较关注的是你是否考虑到位运算的替代方案——比如题目限定只包含小写字母,可以用 32 位整数的位掩码来去重,进一步降低空间占用。
我的建议是:笔试阶段用set是最稳妥的,简单易懂,不易出错。如果要展示能力,可以在注释里提一句“若字符集限定为 a-z,可使用位掩码优化”,不必在代码里真的实现。
3.2 第二题:LRU 缓存淘汰策略
第二道编程题明显加大难度:实现一个 LRU(最近最少使用)缓存,支持get(key)和put(key, value)两个操作,容量为 n,要求在 O(1) 时间复杂度内完成读写。
这是面试经典题,实际笔试时不一定直接叫 LRU,可能包装成一个场景:音乐APP的播放记录缓存,最多保存 n 条,超出后移除最久未使用的记录。
class LRUCache: def __init__(self, capacity: int): self.capacity = capacity self.cache = {} # key -> node, 使用双向链表记录访问顺序 self.head = Node(0, 0) # 虚拟头节点 self.tail = Node(0, 0) # 虚拟尾节点 self.head.next = self.tail self.tail.prev = self.head def _move_to_tail(self, node): # 先摘除节点 node.prev.next = node.next node.next.prev = node.prev # 再移到末尾 node.prev = self.tail.prev node.next = self.tail self.tail.prev.next = node self.tail.prev = node def get(self, key: int) -> int: if key not in self.cache: return -1 node = self.cache[key] self._move_to_tail(node) return node.value def put(self, key: int, value: int) -> None: if key in self.cache: node = self.cache[key] node.value = value self._move_to_tail(node) return if len(self.cache) >= self.capacity: # 移除最久未使用的节点,即头节点之后的第一个 lru = self.head.next del self.cache[lru.key] self.head.next = lru.next lru.next.prev = self.head new_node = Node(key, value) self.cache[key] = new_node new_node.prev = self.tail.prev new_node.next = self.tail self.tail.prev.next = new_node self.tail.prev = new_node关键点在于:为什么 LRU 必须用哈希表+双向链表?哈希表保证 O(1) 的查找,双向链表保证 O(1) 的结点删除与移动。如果用数组来维护访问顺序,移动元素最坏情况是 O(n),在容量很大的时候性能会崩。
笔试平台上默认支持 Python3,Node类需要自己定义。我当时的写法是把Node类定义在LRUCache外部,避免嵌套类导致平台解析异常。如果你用 C++ 写,std::list配合std::unordered_map是更快的写法。用 Java 则可以直接继承LinkedHashMap重写removeEldestEntry方法,代码量更少。
编程题这里我花了较多篇幅,因为它是笔试中唯一可以完全验证正确性的部分,也是最容易拉开分数的环节。我的建议是:平时刷题一定要重视边界条件,比如capacity == 0、put已存在的 key、缓存满后连续get某个 key 再put新 key,这些边界直接决定代码是否 AC。
4. 测试场景设计题:拉开差距的关键环节
4.1 为什么测试岗笔试一定要考场景设计
场景设计题是测试岗笔试和开发岗笔试最本质的区别。它不考你知识面有多宽,而是考你“面向问题的拆解能力”。给你一个功能或接口,你能不能系统地列出测试点,并且在有限时间内给出可执行、分优先级、覆盖到位且包含异常场景的测试方案。
我当时遇到的第一道场景题是:如何测试一个音乐播放器的“每日推荐”功能。第二道是:如何测试一个支付回调接口的幂等性。
这类题目没有标准答案,但阅卷时一定有几个明确的评分维度:覆盖度、结构清晰度、边界与异常场景、测试优先级划分。你要做的不是把想到的点随意罗列,而是按某种逻辑框架组织你的答案,让阅卷人一眼看出你有测试体系思维。
4.2 功能测试点设计:每日推荐场景
对于“每日推荐”这个功能,很多人的第一反应是列出几个测试用例:“推荐列表是否展示”“点击是否能播放”“推荐是否每天刷新”。这些都对,但都停留在最表面。
我当时是按五个维度展开的:
功能验证:首次进入推荐页数据加载;下拉刷新数据更新;不同用户看到不同推荐列表;推荐位点击后跳转正确;列表滚动加载的性能;离线状态下推荐内容的缓存展示。
推荐算法逻辑验证:这是技术测试岗与普通功能测试不一样的地方。你需要思考推荐算法可能出问题的环节——冷启动用户(新注册无行为数据)如何推荐;低活跃用户是否能拿到推荐;已曝光且用户滑过的内容是否重复出现;推荐结果的多样性是否足够(连续15首风格相同算不算漏洞)。
边界与异常:推荐接口在弱网环境下超时是否走兜底逻辑;返回数据为空时页面是否白屏;网络断开后点击推荐位是否有统一错误提示;服务器返回数据字段缺失时是否会导致渲染异常。
交互与体验:推荐列表快速滑动是否出现卡顿或错位;点击推荐位进入播放页后返回是否保持原浏览位置;整个列表滑到底部是否有加载态和结束态。
埋点与日志:推荐位的曝光埋点是否准确;点击埋点是否带上推荐位ID;推荐结果的分页参数是否记录完整。测试岗在笔试阶段提到埋点与日志,会明显展示出工程经验。
把这五点按优先级排列:功能验证 > 边界异常 > 算法逻辑 > 交互体验 > 埋点日志。先保证主流程可用,再覆盖异常场景,不要一开始就纠结边缘交互而忽略核心链路。
4.3 接口幂等性测试:支付回调场景
第二道场景题“支付回调接口的幂等性”更考验底层功力。为什么系统要做幂等?因为支付回调是异步通知,网络超时后平台会重试,而且重试可能发生在支付成功之后,如果接口不幂等,重复的请求会导致用户被扣两次款、或生成两条订单记录。
这种题在测试岗笔试中出现频率极高,因为支付是几乎所有商业产品的核心链路,幂等设计是保证资金安全的基础。
我的答题结构这样组织:
幂等键验证:请求头是否携带业务订单号;同一个订单号重复请求,返回结果是否一致;不同订单号但相同请求体,是否会错误命中幂等逻辑。
并发场景验证:同一个订单号同时发起两个并发请求,最终数据库只有一条成功记录;使用压测工具验证并发下的幂等性,观察锁竞争是否导致死锁或超时。
重复通知验证:模拟多次回调(比如5次)成功后,查询数据库,订单状态只有一次从“待支付”变为“已支付”;回调通知乱序到达时,旧状态是否覆盖新状态。
重复请求与主流程结合:支付成功后重复回调,是否返回正确的成功标识而不是报错;重复回调是否触发额外的短信/邮件通知;重复回调是否会导致库存重复扣减。
在这里一定要提一个测试人员的“职业病”——记录每一次请求的入参、出参、时间戳,并断言响应结果与数据库状态的一致性。这种思维方式在笔试作答时写进去,会让阅卷人觉得你确实干过测试,而不只是背了理论。
4.4 场景题的高分答题框架
不管是功能场景还是接口场景,推荐用一个固定框架,它是我从多年测试实践中总结出来的,笔试和面试通用:
- 主流程验证:用户能走通这个功能,核心链路正常
- 分支流程验证:核心流程上的各种分支判断,如果条件终止/成功/失败
- 异常与容错验证:网络异常、数据异常、依赖服务异常时系统如何表现
- 边界与极限验证:空数据、大数据量、超长字段、超时、并发
- 兼容性验证:不同浏览器/系统/机型
- 安全验证:越权、注入、敏感数据加密(支付接口必答)
这套框架在笔试时直接套用,答题逻辑清晰,覆盖度也不会太差。每一条下列举具体的测试点,不要只写一句话,至少三分支展开。比如“弱网测试”要拆成弱网超时、弱网重试、弱网丢包、弱网恢复四个具体子场景,才有说服力。
5. 常见问题与避坑经验
5.1 代码题编译失败:输入输出格式
笔试平台最大的坑,就是输入输出格式和你自己本地 IDE 习惯不一样。牛客网的编程题默认从标准输入读取,输出到标准输出,而且很多题目会限定你实现某个函数,而不是直接写整个程序。
我当时第一道字符串题,平台给的模板是def solution(s: str) -> str,只需要实现这个函数即可。但第二道 LRU 题给的模板是类方法内部留空。如果你没有看清模板框架,直接把整个类重写了,就会出现“编译器找不到主入口”的错误。
建议提前在牛客网熟悉至少三套真题的答题环境。本地 IDE 写好代码后,粘贴过去运行时,注意看报错信息是“运行时错误”还是“编译错误”,编译错误往往是语法或缺失类定义导致的,运行错误多半是越界或空指针。
5.2 时间管理:最容易翻车的地方
120 分钟看似充足,实际分配不好就会在最后阶段手忙脚乱。我身边有同学在选择题上花掉了 50 分钟,导致编程题只留了 20 分钟,第二题直接空白提交。
复盘整个考试,合理的时间节奏是:选择题 30 分钟,遇到卡壳超过 1 分钟的直接标记跳过,不要恋战。SQL 题 15 分钟,这题难度其实不算高,但需要仔细观察表结构和输出要求,容易被细节绕进去。编程题 45 分钟,优先完成第一道简单题,第二道看难度决定是否保留完整的 40 分钟。剩下的时间留给场景设计题和回头补做选择题。
先做场景设计题还是先做编程题?我的建议是先做编程题。编程题是客观判分,通过测试用例就能拿分;场景设计题是主观判分,只要你写了框架,多少都会给几分。先拿确定的分,再做不确定的。
5.3 场景题“过于空泛”是低分主因
笔试结束后和几个一起参加的同学交流,发现一个共性:场景设计题大家都能写出“测试列表展示”“测试点击播放”“测试网络异常”这类泛泛而谈的用例,但这些内容阅卷人一天看几百份,根本不会给高分。
真正的高分答案是**“具体的、可执行的、有预设条件的测试步骤”**。比如不要把“测试网络异常”作为一条用例,而是写:
- 使用 Charles 模拟 5s 超时,验证播放页面展示“网络不给力”提示
- 断网后点击推荐位,验证不出现白屏和卡死
- 弱网状态(50kbps)下拉刷新,验证 loading 不超过 3s 且数据完整
每个用例都包含操作步骤、前置条件、预期结果三个要素,这才是技术测试岗应有的素养。缺少任何一项,阅卷人都无法判断你是否真的理解测试执行过程。
5.4 SQL 题:三层嵌套查询要冷静
SQL 大题考的是近7天播放次数最多的 TOP10 歌曲,需要关联用户表、歌曲表、播放记录表,并在聚合后排序输出。难点在于如果存在播放记录为空或重复记录的情况,需要用DISTINCT或GROUP BY子查询去重。
我当时写的思路是先用子查询从播放记录表中聚合出每个歌曲的总播放次数,再关联歌曲表获取歌曲名称,最后按播放次数降序取前10。关键注意点是时间过滤条件应该放在聚合之前,否则会导致统计范围不准确。
这种 SQL 题对测试岗来说很实用,因为线上问题排查经常需要写统计类 SQL 来验证数据是否正常。建议校招前把JOIN、GROUP BY、HAVING、窗口函数这几个知识点练熟,笔试完全够用。
5.5 考试环境的细节坑
最后再说几个环境相关的问题。腾讯音乐这一批笔试是双机位监控,副机位放在侧后方45度角,需要拍到桌面和双手。提前找个光线合适、背景干净的房间,不然拍照质检可能卡住,影响进入考场的节奏。
考试过程中浏览器不要切后台。牛客网笔试系统会检测页面失焦次数,切后台超过一定次数会触发警告,严重时直接交卷。我当时写代码时习惯性地想打开本地文档查函数名,还好忍住了,全靠平时积累硬写。另外把手机调成免打扰,微信通知弹窗不会影响电脑端考试,但手机亮屏如果被副机位识别为作弊,解释起来很麻烦。
注意:不管笔试题目多简单,一定要预留至少 5 分钟检查提交状态。牛客网有些题目支持部分运行、部分提交,确认所有题目都进入“已提交”状态再退出。我见过有人写完没点提交,系统自动交卷时只有答案框没有答案内容。
腾讯音乐这轮笔试整体给我的感觉是:题目设计很贴合业务场景,推荐、播放、支付回调都是他们实际产品链路中的真实功能。你不是在死板地答题,更像是在模拟一次真实的工作任务。如果你能把测试思维从笔试题延伸到复盘过程,每一道错题都追问“为什么这么设计考点”,那这套题刷完,你的收获会比单纯背题大得多。