蚂蚁集团测试开发面经(按一二三面拆分 · 可背诵标准回答版)
一、一面(45~60 分钟 · 项目 + 基础 + 手撕代码)
1. 自我介绍
面试官好,我叫 XXX,XX 学校 XX 专业硕士/本科在读。
我有 X 段测试相关经历:
- 在 XX 公司实习期间,负责 XX 模块的功能测试和接口自动化测试
技术栈方面,我熟悉 Python/Java、MySQL、Redis,能独立编写测试脚本。
蚂蚁集团的业务技术含量高,测试涉及支付安全,对质量要求极高,我很认可,也希望能加入这样的团队。2. 接口和抽象类的区别
1. 抽象类:可以有抽象方法和具体方法
接口:JDK 8 后可以有 default 和 static 方法
2. 抽象类:单继承
接口:多实现
3. 抽象类:可以有构造方法
接口:不能有构造方法
4. 抽象类:可以有成员变量(各种权限)
接口:成员变量默认是 public static final(常量)
选择:表示"是什么"用抽象类,表示"能做什么"用接口3. Redis 做分布式锁怎么实现?
SET key value NX PX timeout
- NX:只有 key 不存在时才设置(保证原子性)
- PX:设置过期时间,防止死锁
- value:设置唯一标识,释放锁时验证是否是自己的锁
释放:用 Lua 脚本保证释放锁的原子性
if redis.call("get", KEYS[1]) == ARGV[1] then
return redis.call("del", KEYS[1])
else
return 0
end
问题:过期了但业务还没执行完?
→ 可以开一个续期线程,定期延长过期时间(Redisson 的看门狗机制)4. 接口幂等性是什么?如何保证?
幂等性:同一操作执行多次,结果和执行一次相同。
场景:支付/下单/退款接口必须幂等
保证方案:
1. 数据库唯一索引:插入时用唯一约束防止重复
2. 分布式锁:SETNX 防止并发
3. Token 机制:提交前获取 Token,提交时验证并删除
4. 状态机:只有特定状态才能流转(待支付→已支付→完成)5. RabbitMQ 用来做什么?
我用过 RabbitMQ 实现定时关单功能。
原理:
1. 用户下单后,发送一条延迟消息到死信队列
2. 等待 15 分钟,检查订单状态
3. 如果未支付,关闭订单,释放库存
RabbitMQ 还可以做什么:
1. 异步处理:用户注册后发邮件/短信,不阻塞主流程
2. 流量削峰:高峰期请求进入队列,后端慢慢处理
3. 分布式事务:用消息队列实现最终一致性6. Spring AOP 怎么实现?
1. AOP = Aspect Oriented Programming,面向切面编程
2. 核心概念:
- Join Point:连接点(方法执行)
- Pointcut:切点(要拦截的方法)
- Advice:通知(拦截后的处理逻辑:前置/后置/环绕/异常)
- Aspect:切面(切点 + 通知)
实现方式:
1. JDK 动态代理:只能代理接口
2. CGLIB 代理:可以代理类(通过继承)
3. Spring 默认:接口用 JDK 代理,类用 CGLIB7. Java 中的锁机制
1. synchronized:
- 修饰实例方法:锁当前对象
- 修饰静态方法:锁整个类
- 修饰代码块:锁指定对象
2. synchronized 锁升级:
无锁 → 偏向锁 → 轻量级锁 → 重量级锁
(JDK 6 之后做了优化,锁可以升级但不能降级)
3. ReentrantLock:
- 可重入锁
- 支持公平锁/非公平锁
- 支持 tryLock 尝试获取锁
- 需要手动释放
4. 死锁:
多个线程互相等待对方持有的资源。
避免:按顺序加锁、设置超时、使用锁顺序检测8. 设计模式:单例怎么写?
python
# Python 单例:懒汉式(线程安全)
class Singleton:
_instance = None
_lock = threading.Lock()
def __new__(cls):
if cls._instance is None:
with cls._lock:
if cls._instance is None:
cls._instance = super().__new__(cls)
return cls._instance9. Java 运行时数据区
1. 堆(Heap):对象实例、数组,GC 管理
2. 栈(Stack):方法调用、局部变量,每个线程独立
3. 方法区(Method Area):类信息、静态变量
4. 本地方法栈:Native 方法
5. 程序计数器:记录当前执行位置
堆的分区:
- 新生代:Eden + Survivor(From + To)
- 老年代:长期存活对象10. 线程池参数和工作流程
线程池参数:
1. corePoolSize:核心线程数
2. maximumPoolSize:最大线程数
3. keepAliveTime:空闲线程存活时间
4. unit:时间单位
5. workQueue:任务队列
6. threadFactory:线程工厂
7. handler:拒绝策略
工作流程:
1. 任务进来,先看核心线程池有没有空闲线程
2. 满了就加入队列
3. 队列满了就创建新线程,直到最大线程数
4. 满了就执行拒绝策略
拒绝策略:
1. AbortPolicy:抛异常(默认)
2. DiscardPolicy:丢弃任务
3. DiscardOldestPolicy:丢弃最老的任务
4. CallerRunsPolicy:由调用线程执行11. 手撕代码:连续子数组最大和
python
def maxSubArray(nums):
max_sum = nums[0]
cur_sum = nums[0]
for i in range(1, len(nums)):
cur_sum = max(nums[i], cur_sum + nums[i])
max_sum = max(max_sum, cur_sum)
return max_sum12. 手撕代码:找出有序数组中两个重复元素
python
def findDuplicate(nums):
# 二分查找
left, right = 1, len(nums) - 1
while left < right:
mid = (left + right) // 2
count = 0
for num in nums:
if num <= mid:
count += 1
if count > mid:
right = mid
else:
left = mid + 1
return left二、二面(60 分钟 · 架构深挖 + 项目)
1. 项目架构相关问题
面试官会深挖:
1. 系统整体架构:画图讲解
2. 微服务拆分:按什么维度拆分,服务间如何通信
3. 数据一致性:分布式事务如何处理
4. 性能瓶颈:哪些地方做了优化
5. 监控告警:如何发现线上问题2. 职业规划
1. 短期(1~2 年):扎实测试技术,能独立负责模块
2. 中期(3~5 年):深入测试开发,能设计测试平台和方案
3. 长期:测试架构师 / 测试团队负责人3. 手撕代码:给定字符串删除特定字符(O(1) 空间)
python
def removeChars(s, chars):
# 用双指针,O(1) 空间
char_set = set(chars)
p = 0
for c in s:
if c not in char_set:
s[p] = c
p += 1
return ''.join(s[:p])4. 手撕代码:stringToInt 实现
python
def stringToInt(s):
s = s.strip()
if not s:
return 0
sign = 1
if s[0] == '-':
sign = -1
s = s[1:]
elif s[0] == '+':
s = s[1:]
result = 0
for c in s:
if not c.isdigit():
break
result = result * 10 + int(c)
result *= sign
result = min(result, 2**31 - 1)
result = max(result, -2**31)
return result三、三面(HR 面 · 稳定性 + 动机)
1. 为什么选择蚂蚁?
1. 蚂蚁是金融科技领域的头部公司,技术实力强
2. 支付业务对质量要求极高,测试工程师能学到很多东西
3. 蚂蚁的分布式系统、大数据等技术都是我感兴趣的方向
4. 团队氛围好,技术分享多2. 对加班的看法
我认为加班要分情况:
1. 项目紧急时,加班是必要的,可以接受
2. 长期来看,应该通过提高效率来减少不必要的加班
3. 我会尽量在工作时间内高效完成任务3. 老家在哪里?父母支持吗?
如实回答,并表示家人支持自己在外地工作。4. 能接受工作地点吗?
如实回答,可以说对杭州/上海等工作地点没有限制。四、蚂蚁集团面试特点总结
蚂蚁一面:Java 基础(集合/锁/线程池)+ Redis + 项目 + 手撕代码
重点:Java 八股要深入,Redis 分布式锁要掌握
蚂蚁二面:架构深度 + 项目深挖
重点:项目要能讲清楚架构设计,技术选型理由
蚂蚁三面:HR 面
重点:稳定性、动机、对蚂蚁的了解