乐于分享
好东西不私藏

软件测试面试:自动化与pytest

软件测试面试:自动化与pytest
仍然这次面试面试,它又要凉了中的题目,问完上云、租户、国产化后,话锋一转,面试官开始问自动化
  1. 你们产品测试团队多少人?如何分工?

  2. 接口自动化是你实现的吗?你负责哪部分?

  3. 是配置化还是要写代码?

  4. 接口之间有依赖、鉴权、token过期、隧道加密,如何设计自动化框架保证稳定?

  5. session、token如何管理?过期如何处理?

前三个问题我按实际情况说了,但语气心虚,因为那个时候感觉不是框架核心搭建者,没有自信。后两个涉及底层机制,有概念但讲不系统。

仔细分析,这几个问题的设置是有梯度的:17-18看参与深度 → 19看抽象能力 → 20-21看是否真的懂底层环环相扣。

现在我结合自己项目里遇到的实际场景,把这些点一个个捋清楚。当然,整理的内容部分,依旧参考了AI给我的方向,介意的话不用往下读。

一、团队分工和我的角色(17-18题)

面试官在考察什么 你到底是框架搭建者还是用例执行者?你的自动化深度够不够?

我当时答得小心翼翼:"有专门的自动化团队搭框架,我在自己测的产品中落地"。非常不自信。

其实可以这样说:

"我们公司有专门的自动化团队负责框架核心——pytest二次封装、公共工具函数、报告模板等。我在产品线的角色是框架落地,不是简单拿过来跑。具体做了几件事:第一,根据产品接口的特点补充了对应的方法,比如我们的登录密码是前端加密传输的,框架原生不支持,我自己在Python里实现了同样的加密过程,才能调通登录接口拿token;第二,把token管理、多接口依赖传参这些产品特有的逻辑封装成fixture;第三,做了多线程优化,全量执行时间缩短了不少。"

做的每一件事都是真实的,只是之前说"落地"两个字,面试官听到的可能是"用别人现成的"——而上面这段话,面试官听到的是"我把一个通用框架适配成了一个产品能用的自动化方案"。

二、配置化还是写代码(19题)

AI分析:这个问题不是在问"你们是哪种",是在问"你知道什么时候该用哪种吗"。

配置化(YAML/JSON/Excel)写代码(Python/pytest)
怎么做写配置文件描述接口和断言写测试逻辑代码
门槛需要编程能力
灵活度简单场景够用,复杂场景兜不住什么都能写
适合场景简单CRUD、快速铺量有依赖鉴权、加密、复杂业务链路

实际团队大多是混合模式:常规接口参数和断言走配置,鉴权、token刷新、加密这些配置表达不了的逻辑写代码兜底。

三、核心机制:token管理、接口依赖、执行顺序(20-21题)

这是五个问题里最核心的部分。我从自己项目里遇到的实际问题讲起。

3.1 登录卡在哪——密码加密

我测的项目,登录接口的密码不是明文传输。前端用加密算法处理后再发给后端。我最开始做自动化,直接跳过登录——每次手动配个token进去,token过期了再手动换。能用,但麻烦麻烦麻烦(AI吐槽我这里的自动化像个笑话...)。

后来下决心攻克:找开发问清楚加密算法和密钥,在Python里复现同样的加密过程,调通登录接口拿到token。

这一步是后面所有自动化能力的基石。登录通了,token才有来源。

3.2 token怎么管——不用等报错了再换

拿到token后,最直接的做法是每个用例开头调一次登录。但比如跑10个用例登录10次,既慢又容易被服务端限流。

用一个全局管理器,token快过期了自己去刷新:

class TokenManager:def __init__(self):self._token=Noneself._expires_at=0def get_token(self):# 每次用例来拿token,顺手看一眼时间if time.time() >self._expires_at-300:   # 提前5分钟刷新self._refresh()return self._tokendef _refresh(self):"""真正去调登录接口,拿新token"""encrypted_pwd=encrypt_password("123456")   # 复现前端加密resp=requests.post("/api/login",json={"username""admin""password"encrypted_pwd})data=resp.json()self._token=data["token"]# 记录过期时间expires_in=data.get("expires_in"3600)self._expires_at=time.time() +expires_in

不是开两个线程在后台盯着 就是用的时候看一眼。就像你用手机不是雇人24小时盯着电量,而是每次掏出来之前自己瞟一眼——低于20%就找充电宝,还满着就继续用。token也一样,谁要token谁触发检查,一个单线程,一条路走到底。

3.3 怎么提前知道过期时间——看token是哪种

如果是JWT(三段式,用 . 隔开):

token长这样:eyJhbGciOi...eyJ1c2VyX2lkIjo...SflKxwR...

中间那段直接解码就能看到过期时间,不用等服务端报401:

import base64jsonpayload=token.split(".")[1]      # 取中间那段payload+="="* (4-len(payload%4)    # JWT的base64要补=号data=json.loads(base64.urlsafe_b64decode(payload))print(data["exp"])    # 过期时间戳,直接拿到了

如果不是JWT(一长串乱码,不分段):

token本身不包含任何信息。只能看登录接口的返回值里有没有 expires_in 字段(单位秒),自己算:当前时间 + expires_in = 过期时间。如果接口什么都不返回,就只能兜底——收到401再重新登录。

3.4 pytest的fixture到底干了什么

fixture不是什么高深概念。经AI分析,就是我写的 do_login() 函数,pytest会自动调、自动传结果。没有fixture时,每个用例都得自己调登录,十个用例写十遍。

有fixture之后:

# scope="session" 意思是:整个测试过程只登录一次,所有用例共用@pytest.fixture(scope="session")def token():returnTokenManager().get_token()# 参数里写 token,pytest自动帮你调上面的fixture,把结果传进来def test_查询订单(token):resp=requests.get("/api/orders",headers={"Authorization"f"Bearer {token}"})assertresp.status_code==200def test_创建订单(token):   # 同样,直接用,不用自己登录...

scope控制登录几次:

scope值含义什么时候用
"function"每个用例都调一次(默认)需要完全隔离的数据
"class"一个测试类调一次类内用例共享
"module"一个.py文件调一次按模块隔离
"session"整个测试过程调一次token这种全局共用的

3.5 接口之间有依赖怎么办

举例——登录拿token → 创建订单拿order_id → 支付用order_id。

fixture之间可以嵌套,pytest自动按依赖关系排顺序:

@pytest.fixture(scope="session")def token():"""第一步"""return TokenManager().get_token()@pytest.fixturedef auth_headers(token):"""第二步:依赖token"""return  {"Authorization"f"Bearer {token}"}@pytest.fixturedef created_order(auth_headers):"""第三步:依赖auth_headers"""resp=requests.post("/api/orders"headers=auth_headersjson={...})return resp.json()["order_id"]def test_pay(auth_headerscreated_order):"""第四步:依赖前面全部"""resp=requests.post("/api/pay"headers=auth_headers,json={"order_id"created_order})assert resp.status_code==200

pytest自动排顺序: 不管代码写在前还是写在后,pytest会分析依赖链——token → auth_headers → created_order → test_pay——按这个顺序执行。你不用担心谁先谁后。

3.6 return和yield的区别

fixture里的 return 和 yield,区别只在一个地方——需不需要善后。

# return:交出去就完了(登录拿token就是这种)@pytest.fixturedef token():resp=requests.post("/api/login"json={...})return resp.json()["token"]# 到此结束,后面没有了# yield:交出去→等用例跑完→回来善后(比如关了数据库连接)@pytest.fixturedef db():conn=connect_db()yield conn# 先交出连接,等用例用完conn.close()      # 回来关闭

拿token不需要善后,所以用 return 就够了。

四、隧道加密是什么

面试官问"隧道加密"的时候,我反应了一会。后来问了AI才搞懂。

像平时访问网站,HTTPS本身就是一层加密通道(传输层加密)。请求内容在传输过程中别人看不到。

面试官问的隧道加密通常更进一步——比如政务、金融系统用IPSec隧道或者国密VPN,不仅通道本身加密,传输内容的body可能还要用国密算(SM2/SM3/SM4)再加密一层。

对我们自动化框架的影响分两种:

  • 加密在传输层:框架不感知,requests照常发

  • 加密在应用层(body要SM4加密后才发):框架需要加一层加解密处理

这就跟做登录时"密码要SM4加密"是一个道理——只是不止密码,可能是整个请求body都要加密。

五、问题怎么答嘞

按三层递进:

第一层——角色(17-18):

"框架由自动化团队搭建,我在产品线落地。但落地不是简单执行——比如我们登录密码是前端加密的,框架原生不支持,我在Python里复现了加密过程;token管理、多接口依赖也封装成了fixture。"

第二层——实现方式(19):

"配置和代码混合。常规接口走配置减少重复,鉴权、token刷新这些复杂逻辑写代码兜底。"

第三层——底层机制(20-21):

"token管理用了一个全局管理器,每次用例取token时检查过期时间,提前5分钟自动刷新——不是后台监视线程,就是调用时看一眼。整个测试过程只登录一次,scope设为session。接口依赖通过fixture嵌套,pytest自动按依赖链编排执行顺序。"

面试官从回答里挑关键词往下追问——说fixture他就问fixture怎么用,说token他就问token怎么刷新(理想情况是这样的)。所以说的每个点,都要准备好被追一层。

这也反过来说明一件事:简历上写了的、项目讲述时主动展开的,就是面试官的提问方向。 擅长哪方面,就有意识多说几句细节,把它们变成我的主场。面试官的问题链,往往是自己递过去的话头。

答不好,不是因为没做过,是因为做过的事没整理成体系。现在回头看——做过加密登录、写过token管理、用过fixture——每件事都是对的,只是缺一个框架把它们串起来。

End.-----碎碎念-----💪

我最近不是写这场面试的问题总结,就是这家我很想去的公司。嗯,听朋友说他们又招人了,那我可以确信,确实是我面试过程中有一些问题,不是像当初hr给我的婉拒理由,说他们战略有调整,暂时不招人了,那就是不适配,无缘咯

所以为什么更新这么快,因为受刺激了,要继续总结才行啊,也时不时的刷boss,又开始收藏岗位了,没想到还能变相督促,加油加油继续加油。

不管拿不拿offer,都希望你心想事成!