如何解决pytest+Selenium并行测试中的OTP登录冲突问题
pytest多节点并行下OTP登录问题的解决方案
方案1:为每个测试节点分配独立测试账号
这是最直接的解决方案,彻底避免账号冲突:
- 维护一个测试账号池,每个账号绑定独立的Google Authenticator密钥
- 在参数化
service_data时,为每个测试用例/节点分配唯一账号 - 每个worker启动时从账号池中获取未被占用的账号,登录时使用对应账号的OTP
示例代码:
import pytest from your_auth_module import generate_otp, login # 测试账号池,每个账号包含用户名、密码、OTP密钥 TEST_ACCOUNTS = [ {"username": "user1", "password": "pass1", "otp_secret": "secret1"}, {"username": "user2", "password": "pass2", "otp_secret": "secret2"}, # 更多账号... ] @pytest.fixture(scope="session", params=TEST_ACCOUNTS) def service_data(request): return request.param @pytest.fixture(scope="session") def logged_in_session(service_data): # 生成当前账号的专属OTP otp = generate_otp(service_data["otp_secret"]) # 登录 session = login( username=service_data["username"], password=service_data["password"], otp=otp ) yield session # 登出清理 session.logout()
方案2:将登录fixture的作用域调整为函数/类级
如果账号资源有限,可放弃session级复用,让每个测试用例独立登录:
- 将
setup_module替换为函数级fixture,确保每个用例执行时生成最新的OTP并登录 - 虽然会增加测试执行时间,但彻底解决OTP复用和次数超限问题
示例代码:
import pytest from your_auth_module import generate_otp, login @pytest.fixture(scope="function") def logged_in_session(service_data): # 每次执行用例时生成新的OTP otp = generate_otp(service_data["otp_secret"]) session = login( username=service_data["username"], password=service_data["password"], otp=otp ) yield session session.logout()
方案3:实现分布式锁控制OTP生成与使用
如果必须共享单个账号,可通过分布式锁确保同一时间只有一个节点使用OTP:
- 使用Redis等分布式存储实现锁机制,每个节点在生成OTP前获取锁,使用完成后释放锁
- 锁的有效期需略长于OTP的有效期(通常30秒),避免锁提前释放导致冲突
示例代码:
import pytest import redis import time from your_auth_module import generate_otp, login # 初始化Redis客户端 redis_client = redis.Redis(host="your_redis_host", port=6379, db=0) LOCK_KEY = "otp_login_lock" LOCK_EXPIRE = 35 # 比OTP有效期多5秒 @pytest.fixture(scope="session") def logged_in_session(service_data): # 获取分布式锁 while not redis_client.set(LOCK_KEY, "locked", ex=LOCK_EXPIRE, nx=True): time.sleep(0.5) # 等待锁释放 try: # 生成最新OTP并登录 otp = generate_otp(service_data["otp_secret"]) session = login( username=service_data["username"], password=service_data["password"], otp=otp ) yield session finally: # 释放锁 redis_client.delete(LOCK_KEY) session.logout()
方案4:使用测试环境专属的OTP绕过机制
如果测试环境支持,可申请绕过OTP的测试账号或API:
- 联系运维或开发团队,创建无需OTP验证的测试账号
- 或者使用测试环境专属的登录接口,跳过OTP步骤
- 这是最高效的解决方案,完全避免OTP相关问题
内容的提问来源于stack exchange,提问作者Satyam Agrawal
相关产品推荐
相关产品推荐

