You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何解决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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 01:38:18