pytest中token的一种处理方法

 在某个场景中,各个接口经常需要使用到token,而且接口对频繁登录做了防抖,无法频繁调用。考虑了很多方法,发现总是有一些或多或少的弊端,这里在conftest中定义了一个钩子函数用于处理token。

@pytest.fixture(scope="module")
def auth_tokens(refresh_threshold=600):  # 假设刷新阈值为10分钟
    tokens = {}
    def get_or_refresh_token(username):
        token_info = tokens.get(username)
        if not token_info or (time.time() - token_info['timestamp']) > refresh_threshold:
            logger.info(f"没有获取到该账号{username}的token,或者token已过期,重新获取token中")
            token = login_user(username, '222222').response.json()['data']['accessToken']
            tokens[username] = {'token': token, 'timestamp': time.time()}
        logger.info(f"{username}的token为{tokens[username]['token']}")
        return tokens[username]['token']
    return get_or_refresh_token

作用域定义为模块级,在整个模块中只执行一次。

定义了一个get_or_refresh_token闭包,该闭包负责根据用户名获取或刷新token。虽然auth_tokens fixture在模块级别只实例化一次,但是它返回的闭包(get_or_refresh_token)能够对每个传入的用户名进行独立的操作,确保每个账号的token都是根据需要获取或刷新的。

<think>我们参考了用户提供的三个引用,这些引用主要讨论了pytest中fixture的作用域(scope)及其使用场景。根据这些引用,我们可以总结如下: 引用[1]指出:当fixture定义在一个测试类中时,只有该类中的测试函数可以调用此fixture,类似于局部变量;当定义在模块的全局范围时,模块下的所有测试函数都可以调用它,类似于全局变量。 引用[2]展示了`scope='session'`的fixture,它可以跨多个.py模块调用,并且在整个测试会话中只执行一次。这种fixture通常放在`conftest.py`文件中,以便多个测试模块共享。 引用[3]则展示了`scope='function'`的fixture,这是默认的作用域,每个测试函数都会执行一次。同时,该引用还展示了fixture之间的依赖关系(例如`shop_init`依赖于`login_init`)。 根据这些引用以及pytest官方文档,我们可以总结pytest中fixture的作用域及其适用场景。 ### pytest中fixture的作用域 pytest的fixture作用域通过`scope`参数定义,共有四种作用域: 1. **function**(函数级)[^3]: - **作用范围**:每个测试函数或方法执行一次。 - **适用场景**:适用于需要为每个测试用例提供独立初始化和清理操作的场景,例如数据库事务、临时文件创建等。 - **示例**:每个测试用例都需要一个干净的数据库环境,执行后回滚事务。 2. **class**(类级): - **作用范围**:每个测试类执行一次,无论类中有多少测试方法。 - **适用场景**:当一个测试类中的所有测试方法需要共享相同的初始化状态时,例如创建同一个类的实例供所有测试方法使用。 - **示例**:测试一个用户管理类,所有测试方法都需要一个已初始化的用户管理器实例。 3. **module**(模块级): - **作用范围**:每个测试模块(即一个.py文件)执行一次。 - **适用场景**:当一个模块中的多个测试用例需要共享相同的资源(例如数据库连接、配置文件读取)时使用。 - **示例**:一个测试模块中的所有测试用例都需要使用同一个数据库连接池。 4. **session**(会话级)[^2]: - **作用范围**:整个测试会话(即一次pytest命令执行过程)只执行一次。 - **适用场景**:适用于需要全局共享且开销较大的资源,例如启动一个全局的Web服务器、初始化一个全局的配置等。 - **示例**:多个测试模块都需要访问同一个已启动的Web服务,该服务在整个测试过程中只需要启动一次。 ### 作用域的执行顺序 当多个fixture具有不同的作用域并存在依赖关系时,pytest会按照作用域由大到小的顺序执行(即session > module > class > function)。例如,一个function作用域的fixture依赖于一个module作用域的fixture,那么module作用域的fixture会先执行。 ### 使用建议 - **最小化作用域**:尽量使用满足需求的最小作用域,避免不必要的资源占用和测试之间的相互影响。 - **跨模块共享**:如果需要在多个测试模块中共享fixture,应将其定义在`conftest.py`文件中,并选择合适的作用域(如session或module)[^2]。 - **清理操作**:使用`yield`语句来定义清理操作,确保资源在使用后被正确释放。无论作用域如何,清理操作会在对应作用域的最后一个测试完成后执行。 ### 示例代码 以下是一个包含不同作用域fixture的`conftest.py`示例: ```python # conftest.py import pytest # session级别的fixture,整个测试会话只执行一次 @pytest.fixture(scope="session") def database_connection(): print("建立数据库连接(整个会话)") conn = create_database_connection() yield conn print("关闭数据库连接(整个会话)") conn.close() # module级别的fixture,每个测试模块执行一次 @pytest.fixture(scope="module") def shared_config(database_connection): # 依赖session级别的fixture print("读取模块共享配置") config = load_config() yield config print("清理模块配置") # function级别的fixture,每个测试函数执行一次 @pytest.fixture(scope="function") def clean_data(database_connection): # 依赖session级别的fixture print("初始化测试数据(每个测试函数)") setup_test_data() yield print("清理测试数据(每个测试函数)") clean_test_data() ``` ### 总结 | 作用域 | 执行频率 | 适用场景 | |----------|------------------------|---------------------------------------------| | function | 每个测试函数执行一次 | 每个测试需要独立环境(如事务、临时文件) | | class | 每个测试类执行一次 | 类中所有测试方法共享相同初始化状态 | | module | 每个测试模块执行一次 | 模块内多个测试用例共享资源(如数据库连接) | | session | 整个测试会话执行一次 | 全局共享且开销大的资源(如启动服务) | 正确选择fixture的作用域可以提高测试效率并减少资源消耗。 §§ 相关问题 §§ 1. 如何在pytest中实现fixture之间的依赖注入? 2. 如何避免不同作用域的fixture之间的冲突? 3. 在pytest中,如何为fixture设置自动清理机制? 4. 如何跨多个项目共享pytest fixture? 5. 如何调试pytest fixture的执行顺序问题? > 参考文档: > Pytest官方文档:https://docs.pytest.org/en/stable/fixture.html</think>### pytest fixture 作用域详解 在 pytest 中,fixture 的作用域(scope)决定了 fixture 被创建和销毁的时机。正确理解不同作用域的适用场景可以显著提高测试效率和资源利用率。以下是 pytest 支持的四种作用域及其适用场景: #### 1. `function`(函数级)[^3] - **作用范围**:每个测试函数执行一次 - **适用场景**: - 需要为每个测试提供独立初始化的资源(如临时文件、数据库事务) - 需要测试后立即清理的资源(如内存缓存) - 测试间需要完全隔离的场景 - **特点**: - 默认作用域 - 执行频率最高 - 资源隔离性最好 - **示例**: ```python @pytest.fixture(scope="function") def db_transaction(): # 每个测试函数开始前开启新事务 transaction = start_transaction() yield transaction # 每个测试函数结束后回滚事务 rollback(transaction) ``` #### 2. `class`(类级) - **作用范围**:每个测试类执行一次 - **适用场景**: - 类中所有测试方法共享相同初始化 - 初始化成本较高但可在类内复用的资源 - 测试类级别的状态管理 - **特点**: - 一个类中多个测试共享同一实例 - 比 function 作用域更高效 - **示例**: ```python @pytest.fixture(scope="class") def browser_instance(): # 整个测试类共享一个浏览器实例 browser = launch_browser() yield browser browser.quit() ``` #### 3. `module`(模块级) - **作用范围**:每个测试模块(.py 文件)执行一次 - **适用场景**: - 模块内所有测试共享的资源(如配置文件、数据库连接池) - 需要跨测试类共享的全局状态 - 初始化成本较高的资源 - **特点**: - 模块内所有测试共享同一实例 - 减少重复初始化开销 - **示例**: ```python @pytest.fixture(scope="module") def api_client(): # 整个模块共享的 API 客户端 client = APIClient(config=load_config()) yield client client.cleanup() ``` #### 4. `session`(会话级)[^2] - **作用范围**:整个测试会话执行一次(跨多个模块) - **适用场景**: - 全局共享资源(如 Docker 容器、测试数据库) - 初始化成本极高的资源(如机器学习模型加载) - 需要跨多个测试模块共享的状态 - **特点**: - 必须定义在 `conftest.py` 文件中 - 整个测试生命周期只初始化一次 - 资源利用率最高 - **示例**: ```python # conftest.py @pytest.fixture(scope="session") def test_database(): # 整个测试会话共享的数据库 db = setup_test_db() yield db teardown_test_db(db) ``` ### 作用域优先级与依赖关系[^3] 当 fixture 存在依赖关系时,pytest 按作用域从大到小执行: ```mermaid graph LR A[session] --> B[module] B --> C[class] C --> D[function] ``` **依赖示例**: ```python # 会话级fixture @pytest.fixture(scope="session") def auth_token(): return get_auth_token() # 模块级fixture依赖会话级 @pytest.fixture(scope="module") def api_client(auth_token): # 依赖会话级fixture return APIClient(token=auth_token) # 函数级fixture依赖模块级 @pytest.fixture(scope="function") def user_data(api_client): # 依赖模块级fixture return api_client.create_test_user() ``` ### 最佳实践建议 1. **优先选择最小作用域**:默认使用 `function` 保证测试隔离性 2. **合理提升作用域**:当初始化成本高且测试无状态依赖时,提升到 class/module 3. **会话级资源管理**:将重量级资源设为 `session` 级并放在 `conftest.py`[^2] 4. **避免跨作用域污染**:不要在更大作用域的 fixture 中修改可变状态 5. **清理资源**:使用 `yield` 确保资源释放,无论作用域大小 > 不同作用域的 fixture 组合使用,可以实现从细粒度隔离到高效资源共享的平衡,满足不同测试场景的需求。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值