小红书2020校招笔试题卷三(测试开发&后端)复盘:考点拆解、解题思路与避坑实录
每年校招季,都有大量同学被测试开发和后端这两个方向的笔试题卷搞得焦头烂额。我手上正好翻到一份小红书2020年的校招笔试题卷三,虽然时间过去几年,但这类大厂笔试的考察逻辑和知识点范围,其实年年都差不多,换汤不换药。这份卷子既考后端的基础功底,又考测试开发的业务思维,对于准备校招的同学来说,复盘价值很高。这篇文章我就从岗位差异、核心考点、典型题型和备考策略四个维度,把这份卷子拆开揉碎,结合我自己的刷题和面试经验,聊聊一份合格的笔试答卷到底该怎么写,适合正在准备大厂校招的测试开发、后端岗位候选人参考。
1. 试卷背后的考察逻辑与岗位差异
1.1 为什么一份卷子同时覆盖测试开发与后端
把测试开发和后端放进同一份试卷,是很多大厂的常见操作。小红书这类以内容社区和电商为核心业务的平台,技术团队需要同时保证后端服务的稳定性和业务质量的可控性,两类岗位在笔试题上会有交集,但侧重点完全不同。
从出题逻辑来看,后端岗位更看重对系统设计、数据结构、数据库、网络协议等底层功底的掌握程度,核心是“能不能把功能做出来、做稳定”。而测试开发岗位除了要具备一定的代码能力,还要额外考察测试思维、用例设计、自动化框架理解、问题定位能力,核心是“能不能把质量守住、把问题找出来”。所以你会发现,一份卷子里会有共用题目,比如基础算法、数据库查询,也会有针对不同岗位的附加题或选做题。
1.2 测试开发与后端考察维度的核心差异
我在辅导学弟学妹的过程中,经常被问到“测试开发是不是比后端简单”。其实不存在简单的说法,只是考察维度不同。后端岗位的题目往往更偏重深度,比如让你设计一个高并发下的缓存方案,或者在限定资源下优化某个接口的性能。测试开发岗位则更偏重广度加工程化思维,比如给你一个功能模块,让你列出完整的测试用例,或者让你设计一套自动化测试流水线。
以这份试卷为例,共用的编程题部分,后端和测试开发都需要完成,但针对测试开发的附加题可能会考察你对接口返回结果的断言能力、对异常场景的覆盖能力,而后端的附加题则可能是让你分析一个线上问题的排查思路。这提醒我们,备考时必须锚定自己的目标岗位,不要用一套思路去应对所有题目。
1.3 大厂笔试题的通用出题原则
大厂笔试的出题原则基本可以归纳为三个:基础扎实、思维清晰、工程落地。基础扎实指的是数据结构、操作系统、网络、数据库这些计算机基本功,这是所有岗位的必考题。思维清晰指的是面对开放式问题时,能否条理分明地给出分析和方案,而不是想到哪写到哪。工程落地则是看你能不能把理论转化为可运行的代码、可执行的测试计划,而不是只会背概念。
小红书2020校招笔试题卷三整体上遵循了“由易到难、由基础到综合”的节奏,前面部分是选择题和基础问答题,后面是编程题和场景设计题。这种设计其实很考验时间分配能力,很多人栽在前期小题上纠结太久,导致后面的大题没时间写,这个坑我后面会单独展开讲。
2. 测试开发方向核心考点拆解
2.1 测试用例设计题的答题框架
测试开发笔试卷里几乎必考的,就是给你一个功能,让你设计测试用例。这份试卷里出现的登录功能测试用例设计,是个特别经典的题目,几乎所有大厂都考过。很多同学答题时只会写“输入正确账号密码能不能登录成功”这一条,显然拿不到高分。
完整的测试用例设计应该覆盖功能测试、接口测试、兼容性测试、安全测试和性能测试几个维度。功能测试里又包括正常场景、异常场景和边界场景。以登录为例,正常场景不仅仅是正确账号密码,还包括记住密码、自动登录、切换账号等衍生功能。异常场景要覆盖密码错误、账号不存在、账号被锁定、验证码过期。边界场景则是密码长度的最大最小值、账号含特殊字符、输入框前后空格等。
接口测试维度需要关注返回码是否正确、错误信息提示是否准确、并发登录时是否有竞态问题。兼容性测试要覆盖不同操作系统、不同浏览器、不同分辨率下的表现。安全测试要关注是否有SQL注入风险、密码传输是否加密、是否支持暴力破解防护。性能测试则要关注高并发下登录接口的响应时间和成功率。把这些维度展开来写,一份测试用例设计题就能写出十几条高质量的测试点,得分自然就上去了。
2.2 自动化测试与测试框架的高频考点
自动化测试相关题目在这份卷子里也有不少,主要集中在Selenium的使用、接口自动化测试流程、断言的设计原则这几个方向。Selenium的考察点主要是元素定位方式(id、name、class name、xpath、css selector)的优劣对比,以及显式等待和隐式等待的区别。很多同学容易把Page Object模式忽略掉,实际上在大厂笔试中,问“如何设计一个可维护的UI自动化测试框架”时,Page Object几乎是标准答案的核心。
接口自动化测试的考点则更接近后端工程实践。请求方法的选取(GET和POST的语义区别)、鉴权方式(token、cookie、签名)、断言设计(状态码断言、业务码断言、数据校验断言),这些都是必考内容。值得一提的是,断言设计有一个重要原则,就是“断言结果而不断言过程”,不要只检查HTTP 200就认为接口没问题,要深入到业务返回码和数据字段层面校验。
做接口自动化测试时,数据构造和数据清理经常容易被忽视,但在笔试中写出来会加分。每次跑完测试后,如果测试数据没有清理干净,会影响下一次执行的结果,所以规范的自动化框架里必须有数据准备和数据清理的钩子函数。在答题时主动提到数据管理方案,会让面试官觉得你确实有实践经验。
2.3 常用Linux命令与日志排查必考题
测试开发日常工作中,大量时间花在环境部署和线上问题排查上,所以Linux命令是笔试中不可避免的考点。这份试卷里涉及的考点包括:查看进程(ps -ef | grep java)、查看端口占用(netstat -tlnp)、日志查看(tail -f、grep、awk、sed)、文件权限管理(chmod、chown)、定时任务配置(crontab)等。
很多同学容易忽略的知识点是awk和sed的高级用法。比如在日志中统计某个接口的请求次数和平均响应时间,用awk可以一行命令搞定,这类场景在工作中几乎天天碰到。另外,查找大文件和清理磁盘空间也是高频场景,du -sh *、df -h、find / -size +100M这类命令组合要熟练到不用思考。
日志排查类题目通常会结合具体场景,比如“线上接口超时,如何从日志入手排查问题”。完整的排查思路应该是:先确认现象(哪个接口、什么时间段、成功率多少),再查看应用日志(有没有异常堆栈、慢查询日志),接着查看依赖服务(数据库慢查询、下游服务响应时间、缓存命中率),最后查看系统资源(CPU、内存、磁盘IO、网络带宽)。把这个排查链路写清楚,比背多少命令都管用。
2.4 测试开发的数据结构与算法侧重点
测试开发岗位的编程题通常不会特别难,但也不会白送分。常考的题型包括:字符串操作(反转、去重、最长子串)、数组操作(排序、查找、双指针)、基础的递归和动态规划、LRU缓存设计、单例模式手写。这些题目的核心不是考察你能写出多高级的算法,而是考察代码规范性和边界处理能力。
以字符串反转为例,多数人能写出来,但能考虑到null值处理、空字符串、包含空格、包含Unicode字符的边界情况的就少了一大截。以LRU缓存为例,不少测试开发同学会被这个题目卡住,但其实只要用LinkedHashMap在Java里几行就能实现,关键是要理解LRU本身的淘汰策略内核,再延伸到Redis内存淘汰策略,这样答题时既有代码实现又有理论深度。
我建议测试开发方向的同学刷算法题时,不需要死磕太难的数据结构,但常见题型的代码要写得又快又干净,因为笔试时间有限,编程题往往是决定能否进入面试环节的关键。
3. 后端方向核心考点拆解
3.1 Java基础与并发编程的必考内容
后端方向在这份试卷里以Java技术栈为主,考察内容最集中的就是集合框架和并发编程。集合框架的高频考点包括ArrayList和LinkedList的区别、HashMap的底层实现原理、ConcurrentHashMap在JDK 7和JDK 8中的不同实现方式、HashMap在并发场景下的死循环问题。这些内容几乎属于必答题,没有太多技术含量,但需要理解底层原理而不仅仅是背结论。
以一个常见考法为例,问“HashMap为什么线程不安全”,如果只回答“因为多线程同时put会导致数据覆盖”,只能得基础分。要拿高分得说清楚:JDK 8之前头插法在多线程扩容时可能出现环形链表,导致get死循环;JDK 8改为尾插法后,死循环问题解决了,但put时如果两个线程同时检测到需要扩容,一个线程的数据会被另一个线程覆盖丢失。把底层机制讲清楚,才会让面试官觉得你是真懂。
并发编程方面,synchronized和ReentrantLock的区别、volatile的可见性和指令重排、ThreadLocal的原理和内存泄漏风险、线程池的核心参数和执行流程,都是高频考点。特别是线程池,考察概率极高。核心线程数、最大线程数、阻塞队列、拒绝策略这四大参数的组合逻辑,以及不同业务场景下如何选择参数,一定要形成自己的答题套路。例如IO密集型和CPU密集型任务的核心线程数设置策略差别很大,笔试里把这个分析透,会比较出彩。
3.2 MySQL索引原理与SQL优化
后端笔试题里的MySQL部分,几乎不会绕过索引这个话题。这份试卷中考察了B+树索引结构、聚簇索引和非聚簇索引的区别、联合索引的最左前缀原则,以及explain执行计划中type字段的含义。看起来很常规,但能写全写透的人其实不多。
最左前缀原则是我见过最多人背了但理解不到位的内容。举个例子,联合索引(a, b, c),查询条件只用了b和c,就完全用不上这个索引。但如果查询条件用了a和c,那么只有a能走索引,c是走不了的,因为跳过b之后索引就断了。很多人误以为“条件里有a就算走索引”,其实要区分“走索引”和“索引覆盖”两个概念,这在答题时是明显的分水岭。
SQL优化类的题目,本质上考的是能不能先分析再动手。面对一个慢查询,第一步不是加索引,而是先用explain看执行计划,确认是全表扫描还是索引失效,再针对具体原因做优化。常见的索引失效场景,比如在索引列上做函数运算、隐式类型转换、like以通配符开头、使用or且一侧无索引,每一条都要能举出实际的SQL例子。事务隔离级别、MVCC机制、乐观锁和悲观锁的实现方式,也是后端笔试的常客,需要串联起来形成一个完整的知识体系。
3.3 Redis缓存与高并发场景设计
后端岗位笔试中,Redis的考察重点是缓存穿透、缓存击穿、缓存雪崩三大经典问题及其解决方案。这三个概念极其相似,但本质上完全不同。缓存穿透是查询一个不存在的数据,请求直接打到数据库;缓存击穿是某个热点key过期瞬间,大量请求同时打到数据库;缓存雪崩是大批量key同时过期,导致数据库压力骤增。把这三个场景当成同一件事处理,是很多人在笔试中丢分的主要原因。
针对缓存穿透,常见的解决方案是布隆过滤器或者缓存空对象,两者各有优缺点,布隆过滤器节省空间但有误判率,缓存空对象实现简单但需要设置较短的过期时间。针对缓存击穿,最佳方案是互斥锁,即当key过期后,只允许一个线程去查询数据库并重建缓存,其他线程等待该线程完成。针对缓存雪崩,解决思路是过期时间加随机值、多级缓存、熔断降级,这些方案可以组合使用。
后端笔试还有一类常考的高并发场景设计题,比如设计一个秒杀系统,设计一个短链接服务,设计一个排行榜功能。这类题目考察的是系统设计的全局观。秒杀系统的核心难点在“减库存”的原子性和“限流”策略,思路一般是将请求尽量拦截在缓存层,通过Redis原子操作扣减库存,再异步落库。答题时如果能画出一个请求链路图,并标出每一层的作用和瓶颈,会显得非常专业。
3.4 网络协议与Linux系统知识
网络协议方面,重点考察TCP和UDP的区别、TCP三次握手和四次挥手的过程、TIME_WAIT状态的含义和处理方式、HTTP和HTTPS的区别、HTTP状态码的语义。这些知识点需要达到的条件反射级别,因为在面试环节几乎必问。
TIME_WAIT状态是一个特别容易被深挖的知识点。主动关闭连接的一方在发送最后一次ACK之后,会进入TIME_WAIT状态,持续2MSL时间。原因有两个:一是确保最后的ACK能被对方收到,如果丢包可以重发;二是让旧连接的数据包在网络中完全消失,避免影响新连接。在线上高并发场景下,如果服务器主动断开大量连接,可能会出现TIME_WAIT连接过多导致端口耗尽,这时候一般通过开启tcp_tw_reuse和调整tcp_timestamps来解决,这个从原理到实践的链路是面试官最喜欢的考察方向。
Linux系统知识在后端笔试中,主要考察进程线程模型、孤儿进程和僵尸进程的区别、IO模型(阻塞、非阻塞、多路复用、异步)、零拷贝技术等。其中epoll相对于select和poll的优势是常考题目,重点要讲清楚epoll的三个关键操作(epoll_create、epoll_ctl、epoll_wait)和就绪列表机制,以及为什么epoll在大规模连接场景下性能更好。
4. 高频编程题型的解题思路与代码模板
4.1 大数相加与大数相乘的实现思路
校招笔试的编程题经常考大数处理,因为Java的基础类型和常用库不能直接处理超出范围的大数运算。这份试卷中的编程题部分,也出现了大数相乘的变体。核心思路是用数组模拟手工乘法,先把两个数按照位拆开存成int数组,然后用双重循环逐位相乘并累加,最后统一处理进位。
以字符串形式给出两个数字字符然后相乘为例,算法复杂度是O(n*m),n和m分别是两个数字的长度,空间复杂度是O(n+m)。我在答题时习惯用一个长度为两者长度之和的int数组保存中间结果,因为两个数相乘的乘积位数不会超过两个因数位数之和。然后从后往前遍历数组处理进位,最后把数组中前导的0去掉,再转换成字符串输出。
在笔试现场写这道题时,有两点特别容易出错。一是字符转数字的细节,字符'0'转成整数0需要减48或者减'0',别在细节上翻车。二是处理进位的顺序,一定要从低位到高位逐步处理,而且要记得最高位可能还有进位。写完代码后建议手动跑一个用例,比如"99"乘"99",验证结果是否为"9801",这是最保险的自测方式。
4.2 最长不重复子串:滑动窗口的标准写法
滑动窗口是校招笔试中出现频率最高的算法技巧之一,最经典的载体题目就是求字符串的最长不重复子串长度。这道题看着简单,但很多人在笔试现场写不出bug-free的版本,主要原因是窗口边界的移动逻辑没想清楚。
标准解法是维护一个窗口,用HashMap保存每个字符最近一次出现的位置,用右指针遍历字符串,每次遇到新字符时更新左指针的位置为当前左指针和该字符上一次出现位置加一的较大值,然后更新结果和字符位置。这个思路的关键在于,左指针只会向右移动,不会回退,所以整体时间复杂度是O(n)。
我在刷题过程中总结了一个自查清单:字符串为空时返回值应该是0、字符串长度为1时返回值应该是1、全重复字符时返回值应该是1、全不重复时返回值应该是字符串长度。把这几个边界场景在草稿纸上跑一遍,函数返回正确就不用担心了。笔试时如果时间紧张,完全没有思路的话,可以采用滑动窗口和哈希表这套组合拳来应对大量字符串类题目。
4.3 手写单例模式与线程安全的取舍
后端和测试开发同样经常考到手写单例模式,因为单例模式本身不难,但可以顺带考察并发知识、类加载机制和反射知识。最常要求写的是双重检查锁(DCL)版本,代码并不复杂,但要求解释为什么使用volatile关键字。
volatile在DCL单例中的作用是禁止指令重排序。new Singleton()这一步在JVM层面不是原子的,包含分配内存、初始化对象、将引用指向内存地址三个步骤,如果另一个线程在这三步执行到一半时判断instance不为null,就会拿到一个初始化未完成的对象。volatile可以保证对instance的写操作对其他线程立即可见,并且禁止重排序,这保证了一个线程看到的要么是null,要么是完全创建好的实例。
在答题时,除了DCL版本,主动提到静态内部类方式和枚举方式会让面试官印象更好。枚举方式是最推荐的,因为枚举天然防止反射攻击和序列化破坏,而反序列化可以破坏其他单例实现。虽然笔试手写代码时写枚举可能感觉不太常见,但我建议把三种方式都准备好,并且能说清楚为什么枚举在安全性和简洁性上更胜一筹。
4.4 数据库手写SQL的经典场景
笔试中的SQL手写题,出现频率最高的是这几类:分组统计、多表关联、排名取TopN、行列转换。这份试卷里考察了一个电商场景下的订单统计,要求查询每个用户的最新订单和累计消费金额,核心考点是子查询和窗口函数。
窗口函数在这类题目中非常高效,使用ROW_NUMBER()按用户分组、按时间排序,把每个用户的最新订单标号排为1,然后外层过滤。累计消费金额则用SUM() OVER(PARTITION BY user_id)实现。在面试时用窗口函数通常比传统GROUP BY要好,因为窗口函数能同时保留明细数据和聚合数据,代码也更易于阅读。
很多人在笔试时容易忽略的一个细节是SQL执行顺序。WHERE在GROUP BY之前执行,HAVING在GROUP BY之后执行,所以在WHERE中不能使用聚合函数,但HAVING中可以用。ORDER BY在最后执行,可以使用SELECT中的别名。如果笔试时发现在条件里用了聚合函数且报错,大概率是把WHERE和HAVING用反了。
5. 备考策略与笔试题实战经验
5.1 笔试时间分配与答题节奏
我见过太多同学在笔试中因为时间分配失误而失败的案例。大厂笔试的核心考察点不只是“你会不会”,还有“你在压力下能不能输出”。以一份90分钟的试卷来看,我建议的节奏是:前10分钟浏览全部题目,标记出会做、半会不会、完全不会三类题目;然后优先做完全会做的题,保证基础分不丢;再做半会不会的题,尽量多拿步骤分;最后有时间再去啃完全不会的题。
选择题和填空题不要犹豫太久,一道题超过2分钟还没思路就先蒙一个标记好,等全部做完再回头看。编程题至少要留出40分钟,因为编译运行、调试边界条件都需要时间。很多人倒在做题顺序上:先扎进编程题里死磕一道,结果其他简单题全都没时间碰。更理性的做法是先把简单题做完,心里有底了再集中火力攻难题。
5.2 错题本与刷题路线的搭建方法
准备大厂笔试,不建议拿一本算法书从头啃到尾,那是低效的复习方式。我的建议是以“高频题型+刷题验证”的方式搭建知识体系。先把笔试题中最高频的主题梳理出来,比如字符串、数组、二叉树、动态规划、LRU、手写SQL,针对每一个主题刷20道左右代表性题目,刷完总结出一套模板的写法。
错题本是备考过程中最值的投资。每道错题不用抄完整代码,只记录三样东西:题目类型、我的错误点、正确的解题思路关键词。考前复习时只看错题本,效率比重新刷一遍题高得多。我当年备考时,错题本大概积累了200条记录,考前用两天时间全部过了一遍,相当于把最容易犯的错误系统性地清扫了一遍。
对于测试开发方向的备考,除了算法题之外,一定要额外花时间准备测试用例设计题和自动化框架设计题。这部分没有统一的标准答案,但对考察者来说,“答题是否有结构、是否考虑全面、是否结合了实际测试经验”是最核心的评判指标。从现在开始,拿一个你熟悉的APP功能模块,试着用我前面提到的维度列一份完整的测试用例清单,这个练习比做十套模拟题都管用。
5.3 面试简历中的项目经验与笔试的呼应
笔试和面试是连锁环节,笔试中表现出的知识漏洞,在面试中会被进一步追问。我在准备校招时总结了一个经验:笔试结束后,立刻把自己没有把握的题目全部复盘一遍,把正确的思路和答案整理下来,因为在面试时很可能被问到“笔试中某道题的思路再讲讲”。
同样地,简历上写的项目经历,一定要和你笔试中涉及的技术点保持一致性。如果你的简历写了熟悉Redis,但笔试中Redis相关的题目做得不好,面试官会盯住这个矛盾点深挖。简历中每个技术点,都要准备好一个能讲清楚的真实应用场景,并能把场景背后的技术原理闭卷讲出来。
5.4 一些值得反复咀嚼的实践体会
说几个我自己刷题和笔试过程中反复体会到的教训。第一,代码不是写出来就完事了,自测一定要在草稿纸上做一遍。我吃过太多次亏,写完认为对,一运行就发现数组越界,笔试现场调试时间非常宝贵。第二,不要只刷题不复盘,刷100道题不复盘,不如刷30道题每道都吃透。第三,遇到不会的题千万不要空着,能写多少写多少。笔试是在有限时间内展示你掌握的知识,哪怕是部分思路或者伪代码,也能向考官传达你的思考过程,空着就一点分都没有。
最后再分享一个我近年来辅导备考时的观察:笔试只是起点,面试考察的是你有没有持续学习和自我迭代的能力。一套2020年的笔试题,放到今天来看,核心考点其实没有本质变化。能把这些基础功扎扎实实掌握好的同学,即便遇到没见过的题型,也能凭借稳定的底层知识做出合理推断。考前的焦虑都来自准备不充分,把该刷的题刷透,把该总结的坑总结完,上考场时自然就有底气。