每年秋招季,测试开发岗的笔试都让不少人犯怵。尤其是像TME(腾讯音乐娱乐集团)这种大厂的校园招聘,笔试环节筛人比例一直不低。我去年参加了TME 2024校园招聘的系统测试/测试开发笔试(II),整体感受是:题型不算偏,但覆盖面广,时间紧,而且很看重“测试思维”和“代码落地能力”的结合。这篇文章就把我这次笔试的复盘和还原整理出来,从题型结构、核心考点到编程题思路,再到容易踩的坑,一次性讲清楚。无论你是正在准备大厂测试开发岗的应届生,还是想转岗测试开发、想了解大厂笔试套路的在职测试工程师,这份复盘应该都能给你一些实打实的参考。
1. 笔试整体结构与时间分配复盘
1.1 题型构成与分值分布
TME这套测试开发笔试试卷(II)的整体结构,和多数大厂校招测试岗的试卷差别不大,核心由三大部分组成:客观题(单选+多选)、问答题(简答/场景设计)、编程题。但从分值权重和题目深度上看,它明显更偏向“测试开发”这个复合型岗位,而不是纯粹的功能测试。
我记忆里的题型和分值大致是这样的:
| 题型 | 题量 | 分值占比 | 考察重点 |
|---|---|---|---|
| 单选题 | 约15-20题 | 20%左右 | 数据结构、操作系统、网络、数据库、测试基础 |
| 多选题 | 约5-8题 | 15%左右 | 测试理论、Linux命令、代码阅读 |
| 简答/设计题 | 2-3题 | 25%左右 | 测试用例设计、bug定位思路、测试方案设计 |
| 编程题 | 2题 | 40%左右 | 数据结构与算法、代码实现与调试能力 |
值得留意的是,多选题占比虽然不高,但往往是拉开分差的地方。因为多选漏选、错选都不得分,而且题目经常会设置一些“看起来对但实际偷换概念”的选项,专门用来筛掉基础不扎实的人。我在后面第2部分会详细拆这些考点。
1.2 时间分配策略与答题顺序
整套笔试时间一般是120分钟到150分钟,具体看当年通知。我那次是120分钟,去掉读题和检查,真正有效作答时间其实很紧。我的策略是:先做编程题,再做简答题,最后做客观题,这个顺序可能和很多人习惯的顺序不一样,但实测下来很稳。
先说理由。编程题分值最高,而且大厂笔试的编程题通常不是leetcode那种纯算法题,而是带场景、带业务背景的题目,读题、理解需求、设计思路都需要时间。如果把它放到最后,很容易因为前面客观题耗时太多,导致编程题没时间写甚至直接放弃,那基本就告别下一轮了。
简答题放在第二位,是因为它考察的是测试方案设计、用例编写这类“主观输出”,只要平时有积累,写起来速度会比较快。但这类题不能只写要点,需要展开描述,所以也需要预留充足时间。
客观题放在最后做,是利用它“可快速判断”的特性来兜底。哪怕最后时间不够,多选题也能凭第一印象迅速勾选,不至于大面积空白。当然,这个顺序的前提是你对客观题考点有基础掌握,如果全是知识盲区,顺序怎么调都没用。
2. 计算机基础与专业知识考点深度解析
2.1 数据结构与算法:笔试里的高频考点清单
测试开发笔试中的数据结构题,不会像算法工程师岗那样考到红黑树手写、动态规划优化到极致,但基础数据结构的特性、典型操作的复杂度、常见算法的应用场景必须烂熟于心。
从我这次笔试的还原来看,客观题里数据结构部分主要围绕这几个点展开:
数组和链表的区别:看似基础,但题目会换着花样考。比如问“在尾部频繁插入删除元素,用哪种结构更合适”,很多人第一反应是链表,但实际上如果在尾部操作,动态数组(ArrayList)的均摊时间复杂度也是O(1),而且内存连续、缓存友好,反而更快。这就是一个典型的“面试官挖坑”考点。
栈和队列的应用场景:栈的括号匹配、表达式求值,队列的层序遍历、消息队列模型,这些要能举出具体例子。笔试里常考的是“用两个栈实现队列”这种经典题的变体,比如要求写出入队和出队的平均时间复杂度。
二叉树遍历:前序、中序、后序、层序的递归和非递归实现,要能写出代码。更关键的是,给出两种遍历序列,还原二叉树这种题每年都出现。比如给前序和中序,要能快速确定根节点、划分左右子树。
哈希表的原理与冲突处理:哈希函数设计、链地址法、开放定址法、负载因子对性能的影响。笔试不考手写哈希表,但会考“哈希表在O(1)时间内查找的前提是什么”这类理论题。
排序算法的稳定性与复杂度:快排、归并、堆排、插入、冒泡、选择这六种排序的时间复杂度和是否稳定,几乎是必考。这里有个易错点:堆排序的空间复杂度是O(1),很多人误记成O(n)。还有,快速排序在“数组基本有序”的情况下会退化成O(n²),所以实际工程中常用“三数取中”作为pivot,这个优化思路也会在选择题里出现。
再说说算法部分。笔试编程题和客观题里常见的算法,集中在二分查找、双指针、滑动窗口、DFS/BFS、动态规划入门题(背包、最长子序列)、贪心这几类。TME这套卷子里,编程题不太会出特别偏的题目,但会考察边界条件的处理能力,这个我在第4部分重点讲。
2.2 操作系统、网络与数据库:不容忽视的送分题
这三块内容是测试开发笔试的“基本盘”,题目难度通常不高,但范围很广、考点很碎,容易出现“好像见过,但拿不准”的情况。
操作系统方面,高频考点包括:
- 进程与线程的区别:资源拥有的角度、调度单位、上下文切换开销、通信方式。
- 死锁的四个必要条件:互斥、持有并等待、不可剥夺、循环等待。考题常让你判断某个策略破坏了哪个条件,比如“一次性申请所有资源”是破坏了“持有并等待”。
- 虚拟内存与页面置换算法:FIFO、LRU、LFU的区别,以及LRU的近似实现(比如用哈希表+双向链表,O(1)复杂度)。测试开发岗笔试考到这个,往往不只要懂原理,还要能说出实现思路,因为后面做客户端性能测试、内存泄漏排查时会用到。
- 用户态与内核态:系统调用的开销来源。
计算机网络方面,TCP三次握手和四次挥手是绝对的重点。我那次笔试就考了“为什么握手是三次而不是两次”、“TIME_WAIT状态出现在哪一端、为什么需要”。这两问几乎年年出现,一定要理解背后的原理,而不是死记硬背。另外,HTTP和HTTPS的区别、GET和POST的区别、常见的HTTP状态码(200、301、302、403、404、500、502、503)也要掌握。测试开发岗位特别关注接口测试,所以HTTP协议相关的考点权重会更高。
数据库方面,考点集中在:
- SQL基础语法:SELECT、JOIN、GROUP BY、HAVING、ORDER BY的执行顺序。
- 索引失效的场景:对索引列使用函数、隐式类型转换、like前置通配符、OR连接非索引列等。面接口测试、性能测试的时候,经常要排查慢SQL,所以索引失效是高频考点。
- 事务的ACID特性与隔离级别:脏读、不可重复读、幻读分别对应哪个隔离级别。
- 数据库三范式:第一范式原子性、第二范式消除部分依赖、第三范式消除传递依赖。
这些考点本身不难,但需要系统过一遍。我的建议是,不要只看面经,要动手把SQL写一遍,尤其是涉及多表关联和分组聚合的语句,笔试里是实打实要写的。
3. 测试专业知识与场景题拆解
3.1 测试基础理论:不只是“黑盒白盒”这么简单
测试开发岗笔试里,测试理论部分是最能体现“专业度”的板块。TME这套卷子的客观题涉及了测试金字塔、黑盒测试与白盒测试的常见方法、测试用例设计原则、bug生命周期、测试报告要素等内容。
先说测试金字塔。这个概念近年来越来越常考,因为它直接反映了团队对测试策略的理解:底层是大量的单元测试,中间是较少的接口测试,顶层是更少的端到端测试。题目可能会问“测试金字塔推荐哪种层级的用例数量最多”,或者“以下哪种变更最可能导致测试金字塔失衡”。
黑盒测试方法里,等价类划分、边界值分析、因果图、判定表、场景法、错误推测法是绝对高频考点。尤其是边界值分析,几乎逢考必出。它和应用场景很强,通常是给你一个输入条件(比如“账号密码长度6-16位,可包含字母数字”),让你选出最有效的边界值测试用例。这里有一个我总结的实操技巧:边界值分析时,不光要测边界值本身,还要测边界值两侧的邻界值。比如边界是6和16,有效的测试数据应该是6、7、15、16,无效的是5和17。很多人漏掉7和15这两个点,只测6和16,这是不完整的。
白盒测试方法里的语句覆盖、分支覆盖、条件覆盖、路径覆盖也经常考,而且喜欢让你判断“哪种覆盖标准最强”。这里要记住:路径覆盖最强,但实现代价最高;语句覆盖最弱。另外,MC/DC覆盖(修正条件判定覆盖)是航空级软件认证的标准,有些大厂笔试会考它的概念,核心是“每个条件独立影响判定结果”。
bug生命周期这块比较简单,但要注意,大厂笔试里的流程题往往是“多选”形式,比如“以下哪些状态属于bug生命周期中的状态”,选项包含New、Open、Fixed、Rejected、Closed等。别小看这种题,多选漏选太常见了。
至于测试报告,笔试通常会以简答题形式出现,给你一个测试场景,让你列出测试报告应包含的要素。常规答案是:测试范围、测试环境、测试用例执行情况、缺陷统计与分析、风险与建议。TME这套卷子的简答题,我记得有一道就是“测试活动结束后需要输出哪些内容,请尽可能完整地列出”,这道题几乎就是送分题,关键是不要漏项,能多写不多写。
3.2 测试用例设计题:阅卷人到底在看什么
简答题/设计题是整套卷子里区分度最高的部分,也是TME这类大厂最看重的“测试思维”考察载体。我印象最深的一道题是:设计一个微信语音消息功能的测试用例,要求覆盖功能、性能、兼容性、安全等维度。
这类题看起来很简单,但绝大多数人会栽在“深度不够”上。只写“验证语音能否发送、能否接收、能否播放”这种常规用例,最多拿基础分。阅卷人真正想看到的是:
- 功能维度:录制时长上限、静音录制、中途取消、发送中网络切换、语音转文字、倍速播放、播放时听筒/扬声器切换。
- 异常维度:录制时来电、录制时锁屏、发送时断网、播放时删除消息、文件损坏。
- 性能维度:大文件(如长语音)的发送速度、连续播放的耗电与内存占用、弱网下的延迟和卡顿。
- 兼容性维度:Android和iOS不同系统版本、不同机型分辨率、微信不同版本。
- 安全维度:语音内容加密、隐私保护(陌生人能否查看)、漫游记录同步。
关于测试用例的编写格式,我也是这次笔试后才有更深的体会。大厂阅卷时通常不会要求严格的“用例编号-前置条件-测试步骤-预期结果”四件套格式,但写清楚测试步骤和预期结果是底线。如果只写一个测试点描述,比如“测试语音发送失败”,没有具体步骤和预期结果,阅卷人很难给高分。
从备考角度来说,这类题型是性价比最高的。你不需要刷几千道leetcode,只需要把网上常见的测试用例设计题(比如登录功能、购物车、支付、朋友圈点赞、文件上传下载)系统性过一遍,掌握“功能-异常-性能-兼容-安全”五个维度的拆分思路,就足够应付大部分笔试场景。关键是要形成自己的框架,而不是零散地背题。
4. 编程题实战思路与代码实现
4.1 典型编程题一:字符串处理与边界条件
TME这套卷子的编程题,整体难度在leetcode中等偏下,但很考验代码的严谨程度。我考的题目里,有一道是典型的字符串处理题,大致是:给定一个字符串,将其中连续重复出现的字符压缩成“字符+出现次数”的形式,如果压缩后的字符串长度不小于原字符串,则返回原字符串。
这道题考察的点其实很明确:字符串的遍历、连续字符的计数、条件分支的判断。题目本身不难,但有几个隐藏的坑:
第一,注意空字符串的输入。很多人直接取s[0]访问第一个字符,空字符串会直接越界崩溃。第二,最后一个连续字符组的处理。遍历到字符串末尾时,需要额外把最后一组字符和计数写入结果。第三,压缩结果的比较。题目要求“如果压缩后长度不小于原字符串则返回原字符串”,这个判断要在最后做,而不是边拼接边判断。
我当时的参考代码如下:
def compress_string(s: str) -> str: if not s: return s res = [] count = 1 for i in range(1, len(s)): if s[i] == s[i - 1]: count += 1 else: res.append(s[i - 1] + str(count)) count = 1 # 处理最后一组字符 res.append(s[-1] + str(count)) compressed = "".join(res) return compressed if len(compressed) < len(s) else s # 测试用例 print(compress_string("aabcccccaaa")) # a2b1c5a3 print(compress_string("ab")) # ab(压缩后长度更长) print(compress_string("")) # ""(空字符串)写完之后,我还自己补了几个用例去验证:连续10个相同字符(如”aaaaaaaaaa”)、大小写混合(如”aAa”)、单个字符(如”a”)。这些边界用例在笔试环境里不需要全跑,但在脑子里过一遍必须做到,因为编译环境和判题系统只反馈”通过/不通过“,你不会知道错在哪一组测试用例上。
4.2 典型编程题二:数据结构与模拟类题目
第二道编程题,我印象里是一道模拟队列操作的题,需要实现一个数据结构,支持push、pop、getMin三个操作,getMin要求O(1)时间复杂度。这其实是leetcode 155“最小栈”的变体,但TME把它包装成了队列版本。
这里有一个重要的解题思路转换。最小栈的标准解法是辅助栈:数据栈正常push/pop,辅助栈只push当前最小值,这样getMin就是O(1)。但Java里可以用Deque接口来实现栈和队列,Java的标准API设计得比较合理,这是我实际写代码时的一个体会。
class MinQueue: def __init__(self): from collections import deque self.data = deque() self.mins = deque() def push(self, val): self.data.append(val) if not self.mins or val <= self.mins[-1][0]: self.mins.append((val, 1)) elif val == self.mins[-1][0]: self.mins[-1] = (val, self.mins[-1][1] + 1) def pop(self): if not self.data: return None val = self.data.popleft() if val == self.mins[0][0]: if self.mins[0][1] > 1: self.mins[0] = (val, self.mins[0][1] - 1) else: self.mins.popleft() return val def getMin(self): if not self.mins: return None return self.mins[0][0]这里的关键点有两个。一是需要记录最小值的出现次数。如果最小值被重复入队,只记录一次的话,pop掉一个最小值之后整个最小值记录就丢了。我一开始写的时候忽略了这一点,导致重复最小值的用例直接挂掉。二是队列是先进先出,所以不需要记录下标。如果是最小栈(先进后出),辅助栈的同步pop就解决了问题;但队列的pop是从头部出队,辅助栈的pop也在头部,所以只需要处理头部的最小值计数。
从这个角度来说,最小队列比最小栈多了一个“计数”维度,这是两类题目的本质区别。笔试遇到类似题目时,不要急着写代码,先在草稿纸上理清数据结构和操作的对应关系,会稳得多。
5. 测试开发岗位笔试的准备思路与建议
5.1 从一次笔试看大厂测试开发岗的考察逻辑
复盘完整套试卷之后,我想聊一个更宏观的问题:大厂测试开发岗笔试到底在筛什么样的人?
从TME这套卷子来看,它筛人的逻辑非常清晰,可以用三个关键词概括:扎实的基础、结构化的测试思维、可靠的编码能力。
所谓“扎实的基础”,指的是计算机四大件(数据结构、操作系统、计算机网络、数据库)的掌握程度。这部分题目占比很高,而且难度在一道题内部会做区分。比如同样是考TCP,基础题只问三次握手,拔高题会问SYN Flood攻击的原理,或者TIME_WAIT过多的危害及解决办法。如果你是纯八股文背题选手,遇到拔高题会露馅。
所谓“结构化的测试思维”,指的是面对一个测试场景时,能否系统性地拆解。这里有一个很重要的认知:大厂笔试里的测试设计题,不是让你背用例,而是让你展示你如何搭建测试框架。同样是测一个登录功能,初级答案是“验证用户名密码正确时能登录成功”,进阶答案是“从功能、性能、安全性、易用性、兼容性等多个维度展开”,高级答案则是在进阶基础上,说明为什么优先测某些场景、如何评估风险等级。后面的这种“优先级意识”,恰恰是TME这套卷子简答题里我感受到的考察重点。
所谓“可靠的编码能力”,不是看你写得有多炫酷,而是看你在边界条件、异常处理、代码风格上的自律程度。TME的编程题环境支持本地调试,但判题只看最终结果。很多人平时刷题习惯用IDE的自动补全和调试器,到笔试环境就懵了,连最基本的手写代码都会出现语法错误。我的建议是,备考阶段每周至少做2-3次无IDE辅助的手写编程练习,用在线笔试平台训练,提前适应环境。
5.2 备考路线:从笔试到面试的全链路准备
基于TME这套笔试的复盘,我给正在准备测试开发岗校招的同学一份比较实用的备考路线:
第一阶段,系统性复习计算机基础(建议2-3周)。重点是数据结构中的链表、栈、队列、二叉树、哈希表;操作系统中的进程线程、死锁、虚拟内存;网络中的TCP/IP、HTTP;数据库中的SQL与索引。每一块都要做到能默写核心结论,而不是“看到选项能认出来”。
第二阶段,专项突破测试理论知识(建议1-2周)。推荐《软件测试的艺术》这本书,重点看黑盒测试方法和测试设计思路。同时把牛客网上的测试开发笔试真题刷一遍,感受题型风格。这一阶段的目标是建立“功能-异常-性能-兼容-安全”的五维测试框架,并练习把这个框架迁移到不同的被测对象上。
第三阶段,编程题冲刺(建议至少2周)。每天刷1-2道leetcode简单/中等题,重点覆盖字符串处理、数组操作、二叉树遍历、栈队列应用、二分查找、双指针这几类。注意,不要只刷不看,每道题写完要回头分析:这个解法的时间复杂度是多少?空间复杂度是多少?有没有更优解?这些分析能力在笔试后的技术面里会直接考察。
第四阶段,模拟演练与查漏补缺(建议1周)。找一套完整的测试开发笔试真题,计时、模拟真实环境完整做一遍。做完之后,对照答案解析逐题分析,整理一个“错题本”。这个错题本不要只记录题目和答案,要记录为什么错,是知识盲区、粗心大意,还是时间分配不合理。
我个人在实际备考中还有一个特别深的体会:一定要动手写,而不是只看面经。测试开发笔试里的SQL题、代码题,光看别人的答案永远形成不了自己的解题手感。我备考后期每天固定花1小时在在线OJ上刷题,风雨无阻。最后笔试时,编程题写得非常顺畅,基本没有卡壳,这完全是靠日常手写训练积累出来的手感。
6. 常见失分点与笔试现场避坑实录
6.1 时间分配失控:客观题耗死在多选题上
我笔试时,前30分钟在两道多选题上耗了将近10分钟。原因是那几道多选题考察的是Linux命令和日志分析,选项区分度很小,比如tail和head、grep和awk、ps和top的实际差异。我平时都用图形化工具,这些命令只停留在“看过面经”的层次,真到做题时就开始纠结。
这个问题的根源是对Linux命令只知概念、不知细节。测试开发岗日常要查看日志、排查环境问题,Linux命令是基本功。我建议在备考阶段,专门花半天时间在虚拟机或云服务器上把常用命令都敲一遍,重点掌握这几组容易混淆的命令:
| 命令 | 核心用途 | 易混淆点 |
|---|---|---|
tail -f | 实时跟踪日志输出 | 和tail -n极易混淆 |
ps -ef/ps aux | 查看进程 | -ef与aux用法区别 |
grep/awk/sed | 文本处理三件套 | 各自适用场景不同 |
netstat -tunlp/ss -tunlp | 查看端口监听 | 和telnet区分 |
top/free/df/du | 系统资源监控 | 各自监控对象不同 |
笔试现场如果遇到拿不准的多选题,我的建议是:先标记,跳过,回头再思考。不要在一道题上超过2分钟,否则后面编程题的做题心态和节奏都会被影响。我那次就是多选题耗时过多,导致编程题第一道的思考时间被压缩,差点没写完。
6.2 编程题代码风格与边界条件:细节决定生死
编程题里最容易失分的地方,往往不是思路,而是边界条件处理和代码风格。笔试判题系统通常只反馈「通过/不通过」,不会告诉你哪组用例挂了。所以提交前,先在本地编译器里跑一遍自己设计的边界用例,这能规避很大一部分问题。
我总结了几类常见的边界条件,每道题提交前必须逐一检查:
- 空输入:空字符串、空数组、空链表。
- 单元素输入:长度为1的字符串/数组。
- 输入最小值/最大值:整型溢出风险,python还好,如果用C++或Java要小心。
- 重复元素输入:重复值、全部相同值。
- 特殊格式输入:包含空格、大小写混合、Unicode字符。
代码风格方面,变量命名要清晰规范,缩进统一,逻辑分支要有注释。虽然阅卷系统自动判题时不看注释,但万一笔试被复查,清晰的代码风格会给你加分。更重要的是,笔试完的面试环节,面试官可能会让你复盘笔试代码,这时候代码的可读性直接影响面试官对你的第一印象。
6.3 简答题作答的“结构化”技巧
最后说说简答题/设计题。这类题目没有标准答案,阅卷也是人工评分,所以**“答得有条理”比“答得多”更重要**。
我的作答技巧是:按维度分点作答,每个维度用“场景描述+预期结果”的形式展开。比如要求设计登录功能的测试用例,我会这样作答:
功能维度:验证正确账号密码登录成功、错误密码提示文案、未注册账号提示、密码明文/加密传输、验证码有效期、登录态失效逻辑。
异常场景:连续输错密码是否锁定账户、弱网/断网下的登录行为、切换网络后登录态是否保持。
性能维度:并发100用户同时登录的响应时间、登录接口的压测线程模型、弱网下的超时时间设置。
安全维度:登录接口是否防暴力破解、密码传输是否使用HTTPS、是否存在短信轰炸风险。
这样写的好处是,阅卷人能快速看到你的测试思维是全面的。即便个别场景写得不够细,整体框架已经展示出你具备“测试开发工程师”的基本素养。相反,如果你洋洋洒洒写一大段但没有任何分层,阅卷人很难快速提取信息,得分自然会受影响。
还有一个细节,简答题的作答区一般支持Markdown排版,合理利用列表、加粗、分点,既方便自己梳理,也让阅卷人看着舒服。但要注意,不要为了排版而排版,内容没实质东西,花再多格式也只是花架子。
7. 写在最后:一次笔试带给我的真正启发
说实话,TME这套笔试卷子做完之后,我最强烈的感受不是“题目好难”,而是“原来测试开发岗的笔试是有章法的”。它不会像纯后端岗那样在算法题上往死里卡你,但会在测试理论、场景设计、代码严谨性这些维度上综合考察。这意味着,准备这类笔试不能只靠刷题,更需要建立一套完整的“测试知识体系”。
我个人在备考过程中最大的一次调整,是从“背答案”转向“建框架”。以前我把精力花在记各种测试方法的名字和定义上,以为记住了就能拿分。后来发现,真正拉开差距的,是你能否在一个陌生的测试场景里,快速拆解出功能、异常、性能、兼容、安全等维度,并且针对每个维度给出可执行的测试用例。这种能力只能靠系统性地练习和复盘,没有捷径。
如果你也在准备大厂的测试开发岗笔试,我的建议很简单:早开始、系统学、多动手、勤复盘。把计算机基础打牢,把测试框架内化,把代码习惯养好,笔试对你来说就不会是一座难以跨越的山。最后再分享一个小技巧:每次模拟笔试之后,花30分钟把错题和卡壳点记录到一个文档里,一周后回看一遍,你会惊讶地发现,很多当时觉得难的知识点,其实也就那么回事。